Code Monkey home page Code Monkey logo

macos-notifications's Introduction

macos-notifications

Mac supported Package version Supported Python versions


Documentation: https://jorricks.github.io/macos-notifications/

Source Code: https://github.com/Jorricks/macos-notifications


mac-notification is a Python library to make it as easy as possible to create interactable notifications.

Installation

To use macos-notifications, first install it using pip:

pip install macos-notifications

Features

  • ๐Ÿš€ Easy python interface. It's as simple as 'client.create_notification(title="Meeting starts now!", subtitle="Team Standup")'
  • ๐Ÿ’ฅ Ability to add action buttons with callbacks!
  • ๐Ÿ“ Ability to reply to notifications!
  • โŒš Delayed notifications.
  • โฑ๏ธ Automatically time out the notification listener.
  • ๐Ÿ“ฆ Just pyobjc as a dependency.

Example

from functools import partial
from mac_notifications import client

if __name__ == "__main__":
    client.create_notification(
        title="Meeting starts now!",
        subtitle="Team Standup",
        icon="/Users/jorrick/zoom.png",
        action_button_str="Join zoom meeting",
        action_callback=partial(join_zoom_meeting, conf_number=zoom_conf_number)
    )

A simple example. Please look in the docs for more examples like this:

macos-notifications

Why did you create this library?

I wanted a library that did not depend on any non-python tools (so you had to go around and install that). Instead, I wanted a library where you install the pip packages, and you are done. Later I realised how hard it was to integrate correctly with PyOBJC. Also, I had a hard time finding any examples on how to easily integrate this in a non-blocking fashion with my tool. Hence, I figured I should set it up to be as user-friendly as possible and share it with the world ;)!

Limitations

Although there are some limitations, there is no reason to not use it now โœŒ๏ธ.

  • You need to keep your application running while waiting for the callback to happen.
  • We do not support raising notifications from anything but the main thread. If you wish to raise it from other threads, you need to set up a communication channel with the main thread, which in turn than raises the notification.
  • Currently, we are only supporting the old deprecated user notifications. If you wish to use the new implementation, please feel free to propose an MR.
  • You can not change the main image of the notification to be project specific. You can only change the Python interpreter image, but that would impact all notifications send by Python.

macos-notifications's People

Contributors

basilevs avatar jorricks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

macos-notifications's Issues

Python3.7 install of macos-notifications does not show a notification

  from mac_notifications import client

  client.create_notification(
    title = 'New To-Do',
    text = 'Test', # todo['body'],
  )

causes an error for me:

[greg@imac]> ~/src/utility/gitlab/mac-todo-notifier                                                                                  ๎‚ฒ โœ” ๎‚ณ 04:46:23 PM ๏€—
The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.
The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.

Add optional User Notification support

I can try and help implement support for the supported User Notification API. One issue is that you have to fallback to the old API when your python install isn't codesigned (for example python from homebrew)

You can check if it is supported pretty easily with this

from UserNotifications import UNUserNotificationCenter
def auth_callback(granted, err):
    print("Granted: ", granted)
    print("Error in authorization request: ", err)

c = UNUserNotificationCenter.currentNotificationCenter()
c.requestAuthorizationWithOptions_completionHandler_(0b111111,auth_callback

Icon is blocked?

When running your examples the icon is somehow "blocked"?

image

Is this known?

macOS 12.6
MacBook Pro (14-inch, 2021) M1Pro
Python 3.10.6
macos-notifications    0.1.5
pyobjc-core            8.5
pyobjc-framework-Cocoa 8.5

Doesn't support threading

Got the following error trying to create notification:

  File "/lib/python3.12/site-packages/mac_notifications/manager.py", line 48, in __init__
    signal.signal(signal.SIGINT, handler=self.catch_keyboard_interrupt)
  File "/lib/python3.12/signal.py", line 56, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: signal only works in main thread of the main interpreter

Installation conflicts with latest version of PyObjC

macos-notifications has a dependency pyobjc-core==8.5.
On my machine with the current pyobjc-core (9.0.1), this causes python3 -m pip install macos-notifications to fail.

Would it be possible to upgrade the dependency?

Thanks!

macos-notifications fails to install on CPython 3.11

macos-notifications itself may be OK. But it's probably insisting on having a version of pyobjc-core that is too old for 3.11. Maybe a setup.py problem?

pyobjc-core installs fine on 3.11 if you don't constrain what version it gets - that is, if you install it by itself. But installing macos-notifications tries to install pyobjc-core, and that fails.

MacOSNotification is overriding existing Objective-C class

Hi,
I get this whenever I try to create the second notification. The first one goes out okay and any further call will result in this error. The first notification is still visible, so no one has closed it yet. I suppose that's the problem and it's trying to override the notification that is currently active and visible instead of creating a new one, like slack or any other chat normally does.

I'm using python 3.9 and Mac OS Big Sur.

python3.9/site-packages/mac_notifications/notification_sender.py", line 29, in create_notification
    class MacOSNotification(NSObject):
objc.error: MacOSNotification is overriding existing Objective-C class

One program, two notifications: one notification seems to dismiss the other

I don't really know much about MacOS' notifications, but should one notification that's already up, be knocked down by a second notification?

EG, in the snippet below, I've got 2 notifications in the one program, each notification having 1 callback - but I can't seem to find where to acknowledge "the other one".

Should I block until the first is acknowledged before submitting the second? Is there a way to make the notifications "pile up"?

#!/usr/bin/env python3

import sys
import time

from mac_notifications import client


class Callback:
    def __init__(self):
        self.called_back = False

    def callback(self):
        self.called_back = True

    def __str__(self):
        if self.called_back:
            return 'callback called'
        else:
            return 'callback not called'

    __repr__ = __str__


if __name__ == '__main__':
    popup_list = []
    for i in range(2):
        cb = Callback()
        popup_list.append(cb)
        client.create_notification(
            title="title {}".format(i),
            subtitle="subtitle",
            icon=None,
            action_button_str="Acknowledge",
            action_callback=cb.callback,
        )
    while not all(p.called_back for p in popup_list):
        print('waiting...:', popup_list)
        sys.stdout.flush()
        time.sleep(1)
    client.stop_listening_for_callbacks()
    print('hello!')

Thanks!

macos-notifications 0.1.5 does not give a notification on python 3.10

I'm using homebrew CPython 3.10, macos-notifications 0.1.5 and MacOS 12.6 on an Intel Mac.

This script is what I'm using to test macos-notifications:

#!/usr/bin/env python3

from time import sleep

from mac_notifications import client

if __name__ == '__main__':
    client.create_notification(
        title="title",
        subtitle="subtitle",
        icon=None,
    )
    sleep(60)

I'm running it with:
/usr/local/bin/python3.10 tst

But no notification comes up.

Any suggestions?

Thanks!

mac_notifications-utilizing process never exits

Here's a test program that demonstrates the problem:

#!/usr/bin/env python3

import sys
import time

from mac_notifications import client


def noop(*args, **kwargs):
    """No operation: do nothing."""
    pass


class Callback:
    def __init__(self):
        self.called_back = False

    def callback(self, *args, **kwargs):
        print(f'args: {args}')
        print(f'kwargs: {kwargs}')
        self.called_back = True


if __name__ == '__main__':
    cb = Callback()
    client.create_notification(
        title="title",
        subtitle="subtitle",
        icon=None,
        action_button_str="Acknowledge",
        action_callback=cb.callback,
    )
    while not cb.called_back:
        print('waiting...')
        sys.stdout.flush()
        time.sleep(1)
    print('hello!')

It never exits. It does the print('hello!') fine, but the process just keeps running.

What do I need to do to get the process to exit normally?

Thanks!

notification not shown in macos 13 with python 3.11

env:
device: Macbook Pro M1 Max
MacOS: 13.5.2
python: 3.11.5
macos-notifications version: 0.1.6

codes:

import time

from mac_notifications import client

if __name__ == "__main__":
    client.create_notification(
        title="Meeting starts now!",
        subtitle="Team Standup"
    )
    time.sleep(60)

notification setting:
image

running result:
The program ran normally. But the notification wasn't shown.

Issue with freeze support on Python 3.11

Using macOS 13.5.1 and Python 3.11, I'm unable to run the basic example. I get the following stacktrace:

  File "/Users/mariusshekow/...myfilepath....py", line 8, in send_notification
    client.create_notification(
  File "/Users/mariusshekow/PycharmProjects/myproject/venv/lib/python3.11/site-packages/mac_notifications/client.py", line 66, in create_notification
    get_notification_manager().create_notification(notification_config)
  File "/Users/mariusshekow/PycharmProjects/myproject/venv/lib/python3.11/site-packages/mac_notifications/manager.py", line 69, in create_notification
    new_process.start()
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 121, in start
    self._popen = self._Popen(self)
                  ^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/context.py", line 288, in _Popen
    return Popen(process_obj)
           ^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/popen_spawn_posix.py", line 32, in __init__
    super().__init__(process_obj)
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/popen_fork.py", line 19, in __init__
    self._launch(process_obj)
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/popen_spawn_posix.py", line 42, in _launch
    prep_data = spawn.get_preparation_data(process_obj._name)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/spawn.py", line 158, in get_preparation_data
    _check_not_importing_main()
  File "/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/spawn.py", line 138, in _check_not_importing_main
    raise RuntimeError('''
RuntimeError: 
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

RuntimeError involving freeze_support()

Hi,

Using Python 3.9.4 I try to create a notification with the following line:

client.create_notification("Title TEST", "Subtitle TEST", "Text TEST")

Instead of the notification popping up, the following error is raised:

File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/multiprocessing/spawn.py", line 134, in _check_not_importing_main
    raise RuntimeError('''
RuntimeError: 
        An attempt has been made to start a new process before the
        current process has finished its bootstrapping phase.

        This probably means that you are not using fork to start your
        child processes and you have forgotten to use the proper idiom
        in the main module:

            if __name__ == '__main__':
                freeze_support()
                ...

        The "freeze_support()" line can be omitted if the program
        is not going to be frozen to produce an executable.

Somebody knows what's going on? Would appreciate the help, thanks! ๐Ÿ™๐Ÿป

Link in documentation with instructions on enabling notifications points to a wrong location

Hello,

Link in documentation with instructions on enabling notifications points to a wrong location.

Issue is here:
https://jorricks.github.io/macos-notifications/faq/
you first need to allow Python to create notifications. Instructions on this can be found [here]

And it points to a wrong location:
https://www.jetbrains.com/idea/guide/tips/enable-soft-wrap/#:~:text=You%20can%20enable%20soft%20wrap,more%20file%20types%20by%20default.).

Thanks

Python's icon

Hi Jorricks!

I want to ask you if you've looked into changing the default Python icon that pops up in the notification on the left and, if you have, could you share how to do it.

Thanks for the code!

Missing from the documentation? How to create a persistent notification

I have a program I want to use mac_notifications in.

I need the notification to stay visible until clicked though - timing out after a handful of seconds doesn't work well for this application.

I don't see anything about this in the documentation. The closest seems to be:
:param delay: Delay before showing the message.

Am I missing something?

Thanks!

There is no API to delete notifications

There is no way to close a notification.

For example, there is no need to keep showing "unread messages" notification after messages are read, but the library can't stop showing it.

Examples with callbacks always timeout

When a reply is sent:
Untitled

The Notification still timeout in the example. Is this how it should work? My expectation was that we either get a reply and quit or get no reply and timeout.

macOS 12.6
MacBook Pro (14-inch, 2021) M1 Pro
Python 3.10.6
macos-notifications    0.1.5
pyobjc-core            8.5
pyobjc-framework-Cocoa 8.5

Possible to send notifications to other users and/or send from daemon process?

I tried to call create_notification() from a daemon process that runs as root and it failed with builtins.ValueError: bad value(s) in fds_to_keep. That sort of makes sense given that root isn't a regular user. While I'm not sure this is even possible I was hoping to find a parameter for the userInfo argument that the objective-c NSUserNotification constructor takes and didn't see anything. Would it be possible to implement such a thing? I could maybe help with a pull request.

AttributeError: 'NoneType' object has no attribute 'setDelegate_'

Python 3.11.3, "client.create_notification" returns the following error:

Process NotificationProcess-1: Traceback (most recent call last): File "/Users/rutger/.pyenv/versions/3.11.3/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap self.run() File "/Users/rutger/.pyenv/versions/3.11.3/lib/python3.11/site-packages/mac_notifications/listener_process.py", line 28, in run notification_sender.create_notification(self.notification_config, self.queue).send() File "/Users/rutger/.pyenv/versions/3.11.3/lib/python3.11/site-packages/mac_notifications/notification_sender.py", line 58, in send NSUserNotificationCenter.defaultUserNotificationCenter().setDelegate_(self) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'setDelegate_'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.