From 463d103addbb2f1041adfe6cc2d4a1b328f8e411 Mon Sep 17 00:00:00 2001 From: Matthew Cane <39704070+MatthewCane@users.noreply.github.com> Date: Mon, 11 Nov 2024 14:04:08 +0000 Subject: [PATCH] The view action opens a website or app when the action button is tapped (#32) --- docs/quickstart.md | 5 + docs/reference-auto.md | 184 -------------------- docs/reference.md | 298 +++------------------------------ mkdocs.yml | 30 +++- poetry.lock | 49 +++++- pyproject.toml | 4 +- python_ntfy/_get_functions.py | 11 +- python_ntfy/_send_functions.py | 69 +++++++- 8 files changed, 173 insertions(+), 477 deletions(-) delete mode 100644 docs/reference-auto.md diff --git a/docs/quickstart.md b/docs/quickstart.md index 7ea9ca8..12e6a3e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -11,6 +11,11 @@ # Import the ntfy client from python_ntfy import NtfyClient +# Optionally set your environment variables +from os import environ +environ["NTFY_USER"] = "your_username" +environ["NTFY_PASSWORD"] = "your_password" + # Create an `NtfyClient` instance with a topic client = NtfyClient(topic="Your topic") diff --git a/docs/reference-auto.md b/docs/reference-auto.md deleted file mode 100644 index ebdf18c..0000000 --- a/docs/reference-auto.md +++ /dev/null @@ -1,184 +0,0 @@ -# NtfyClient Documentation - -## Overview - -NtfyClient is a Python package for interacting with the ntfy.sh service or a self-hosted ntfy server. It provides functionality to send notifications and retrieve cached messages. - -## Installation - -You can install NtfyClient using pip: - -```bash -pip install ntfyclient -``` - -## Usage - -### Initializing the Client - -```python -from ntfyclient import NtfyClient - -client = NtfyClient(topic="your_topic", server="https://ntfy.sh") -``` - -## API Reference - -### NtfyClient - -#### `__init__(topic: str, server: str = "https://ntfy.sh")` - -Initialize a new NtfyClient instance. - -- `topic`: The topic to use for this client -- `server`: The server to connect to. Must include the protocol (http/https) - -#### `set_topic(topic: str)` - -Set a new topic for the client. - -- `topic`: The new topic to use for this client - -### Sending Messages - -#### `send(message: str, title: str = None, priority: Optional[MessagePriority] = MessagePriority.DEFAULT, tags: list = [], actions: list[Union[ViewAction, BroadcastAction, HttpAction, None]] = [], format_as_markdown: bool = False)` - -Send a text-based message to the server. - -- `message`: The message to send -- `title`: The title of the message (optional) -- `priority`: The priority of the message (optional, defaults to `MessagePriority.DEFAULT`) -- `tags`: A list of tags to attach to the message (optional) -- `actions`: A list of Action objects to attach to the message (optional) -- `format_as_markdown`: If true, the message will be formatted as markdown (optional) - -Returns the response from the server. - -#### `send_file(file: str, title: str = None, priority: Optional[MessagePriority] = MessagePriority.DEFAULT, tags: list = [], actions: list[Union[ViewAction, BroadcastAction, HttpAction, None]] = [])` - -Send a file to the server. - -- `file`: The path to the file to send -- `title`: The title of the file (optional) -- `priority`: The priority of the message (optional, defaults to `MessagePriority.DEFAULT`) -- `tags`: A list of tags to attach to the message (optional) -- `actions`: A list of Action objects to attach to the message (optional) - -Returns the response from the server. - -### Retrieving Messages - -#### `get_cached_messages(since: str = "all", scheduled: bool = False)` - -Get cached messages from the server. - -- `since`: The timestamp to start from. If set to "all", will return all messages (optional) -- `scheduled`: If true, will return scheduled messages (optional) - -Returns a list of messages. - -### Enums and Classes - -#### MessagePriority - -An enumeration of message priority levels: - -- `MIN`: "1" -- `LOW`: "2" -- `DEFAULT`: "3" -- `HIGH`: "4" -- `MAX`: "5" -- `URGENT`: Alias for MAX - -#### ActionType - -An enumeration of action button types: - -- `VIEW`: "view" -- `BROADCAST`: "broadcast" -- `HTTP`: "http" - -#### ViewAction - -Represents a view action button. - -- `__init__(label: str, url: str, clear: bool = False)` - -#### BroadcastAction - -Represents a broadcast action button. - -- `__init__(label: str, intent: str = "io.heckel.ntfy.USER_ACTION", extras: Optional[dict] = None, clear: bool = False)` - -#### HttpAction - -Represents an HTTP action button. - -- `__init__(label: str, url: str, method: str = "POST", headers: Optional[dict] = None, body: Optional[str] = None, clear: bool = False)` - -## Examples - -### Sending a Simple Message - -```python -from ntfyclient import NtfyClient, MessagePriority - -client = NtfyClient("your_topic") -response = client.send( - message="Hello, world!", - title="Test Message", - priority=MessagePriority.HIGH, - tags=["test", "example"] -) -print(response) -``` - -### Sending a File - -```python -from ntfyclient import NtfyClient - -client = NtfyClient("your_topic") -response = client.send_file("path/to/your/file.txt", title="Important File") -print(response) -``` - -### Retrieving Cached Messages - -```python -from ntfyclient import NtfyClient - -client = NtfyClient("your_topic") -messages = client.get_cached_messages(since="2023-01-01") -for message in messages: - print(f"Message: {message['message']}, Time: {message['time']}") -``` - -### Using Action Buttons - -```python -from ntfyclient import NtfyClient, ViewAction, BroadcastAction, HttpAction - -client = NtfyClient("your_topic") -actions = [ - ViewAction("Open Website", "https://example.com"), - BroadcastAction("Custom Action", extras={"key": "value"}), - HttpAction("API Call", "https://api.example.com", method="POST", body='{"key": "value"}') -] -response = client.send( - message="Message with actions", - title="Action Test", - actions=actions -) -print(response) -``` - -## Environment Variables - -The NtfyClient supports the following environment variables: - -- `NTFY_SERVER`: Sets the default server URL -- `NTFY_USER`: Sets the username for authentication -- `NTFY_PASSWORD`: Sets the password for authentication - -If both `NTFY_USER` and `NTFY_PASSWORD` are set, the client will use them for authentication. \ No newline at end of file diff --git a/docs/reference.md b/docs/reference.md index 975946f..c03d5ae 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,279 +1,19 @@ -# Reference Guide - -## `NtfyClient` - -## Initialiser - -```python -from python_ntfy import NtfyClient - -NtfyClient( - topic: str, - server: str = "https://ntfy.sh" -) -``` - -### Arguments - -**`topic` (required)** - -Type: String -The topic to send messages to. - -**`server`** - -Type: String -Default: `https://ntfy.sh` -The server to send messages to. - ---- - -### Methods - -#### `send` - -```python -NtfyClient.send( - message: str, - title: str = None, - priority: Optional[MessagePriority] = MessagePriority.DEFAULT, - tags: list = [], - actions: list[Union[ViewAction, BroadcastAction, HttpAction, None]] = [], - format_as_markdown: bool = False, -) -> dict -``` - -##### Arguments - -**`message` (required)** - -Type: String -The message to send to the topic. - -**`title`** - -Type: String -Default: `None` -The title of the message. If `None`, the message will have no title. - -**`priority`** - -Type: `Optional[MessagePriority]` -Default: `MessagePriority.DEFAULT` -The priority of the message. Can be one of the values from the `MessagePriority` enum. - -**`tags`** - -Type: `list` -Default: `[]` -A list of tags to associate with the message. - -**`actions`** - -Type: `list[Union[ViewAction, BroadcastAction, HttpAction, None]]` -Default: `[]` -A list of actions to include with the message. Each action can be an instance of `ViewAction`, `BroadcastAction`, `HttpAction`, or `None`. - -**`format_as_markdown`** - -Type: `bool` -Default: `False` -If `True`, the message will be formatted as Markdown. - -#### `send_file` - -```python -NtfyClient.send_file( - file: str, - title: str = None, - priority: Optional[MessagePriority] = MessagePriority.DEFAULT, - tags: list = [], - actions: list[Union[ViewAction, BroadcastAction, HttpAction, None]] = [], -) -> dict -``` - -#### `set_topic` - -```python -NtfyClient.set_topic(topic: str) -> None -``` - -##### Arguments - -**`topic` (required)** -Type: `str` -The topic to send messages to. - -#### `get_cached_messages` - -```python -NtfyClient.get_cached_messages( - since: str = "all", - scheduled: bool = False -) -``` - -##### Arguments - -**`since`** - -Type: `str` -Default: `"all"` -The timestamp to start retrieving messages from. If set to "all", will return all messages. - -**`scheduled`** - -Type: `bool` -Default: `False` -If `True`, will return scheduled messages. - -##### Returns - -Type: `list` -A list of dictionaries containing the cached messages. - ---- - -### Classes - -#### `ViewAction` - -```python -ViewAction( - label: str, - url: str, - clear: bool = False -) -``` - -##### Arguments - -**`label` (required)** - -Type: `str` -The label for the view action button. - -**`url` (required)** - -Type: `str` -The URL to open when the action button is clicked. - -**`clear`** - -Type: `bool` -Default: `False` -If `True`, the notification will be cleared when the action is tapped. - -#### `BroadcastAction` - -```python -BroadcastAction( - label: str, - intent: str = "io.heckel.ntfy.USER_ACTION", - extras: Optional[dict] = None, - clear: bool = False -) -``` - -##### Arguments - -**`label` (required)** - -Type: `str` -The label for the broadcast action button. - -**`intent`** - -Type: `str` -Default: `"io.heckel.ntfy.USER_ACTION"` -The Android intent to broadcast when the action is tapped. - -**`extras`** - -Type: `Optional[dict]` -Default: `None` -Additional key-value pairs to add to the broadcast intent. - -**`clear`** - -Type: `bool` -Default: `False` -If `True`, the notification will be cleared when the action is tapped. - -#### `HttpAction` - -```python -HttpAction( - label: str, - url: str, - method: str = "POST", - headers: Optional[dict] = None, - body: Optional[str] = None, - clear: bool = False -) -``` - -##### Arguments - -**`label` (required)** - -Type: `str` -The label for the HTTP action button. - -**`url` (required)** - -Type: `str` -The URL to send the HTTP request to when the action is tapped. - -**`method`** - -Type: `str` -Default: `"POST"` -The HTTP method to use for the request. - -**`headers`** - -Type: `Optional[dict]` -Default: `None` -Additional headers to include in the HTTP request. - -**`body`** - -Type: `Optional[str]` -Default: `None` -The body of the HTTP request. - -**`clear`** - -Type: `bool` -Default: `False` -If `True`, the notification will be cleared when the action is tapped. - ---- - -### Enums - -#### `MessagePriority` - -An enumeration of message priority levels. - -```python -class MessagePriority(Enum): - MIN = "1" - LOW = "2" - DEFAULT = "3" - HIGH = "4" - MAX = "5" - URGENT = MAX -``` - -#### `ActionType` - -An enumeration of action button types. - -```python -class ActionType(Enum): - VIEW = "view" - BROADCAST = "broadcast" - HTTP = "http" -``` +# API Reference + +::: python_ntfy._ntfy.NtfyClient + options: + show_root_heading: true + show_root_toc_entry: true + show_bases: false + +::: python_ntfy._send_functions + options: + show_root_heading: false + show_root_toc_entry: false + heading_level: 3 + +::: python_ntfy._get_functions + options: + show_root_heading: false + show_root_toc_entry: false + heading_level: 3 diff --git a/mkdocs.yml b/mkdocs.yml index bc0762d..6284d9e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,14 +1,42 @@ site_name: python-ntfy documentation +site_url: https://matthewcane.github.io/python-ntfy/ +site_description: Documentation for python-ntfy, a Python client for ntfy.sh +site_author: Matthew Cane +repo_url: https://github.com/matthewcane/python-ntfy + nav: - Home: index.md - Quickstart: quickstart.md - Examples: examples.md - - Reference: reference.md + - API Reference: reference.md + theme: material + plugins: - search + - mkdocstrings: + default_handler: python + handlers: + python: + options: + show_source: false + show_bases: true + show_labels: false + show_symbol_type_toc: true + show_signature_annotations: true + separate_signature: true + group_by_category: true + merge_init_into_class: true + inherited_members: true + docstring_style: google + heading_level: 2 + markdown_extensions: - admonition - pymdownx.details - pymdownx.superfences - def_list + - toc: + permalink: true + toc_depth: 3 + title: On this page diff --git a/poetry.lock b/poetry.lock index f524453..ac7a943 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "babel" @@ -14,6 +14,50 @@ files = [ [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] +[[package]] +name = "black" +version = "24.10.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +files = [ + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "certifi" version = "2024.8.30" @@ -527,6 +571,7 @@ Markdown = ">=3.6" MarkupSafe = ">=1.1" mkdocs = ">=1.4" mkdocs-autorefs = ">=1.2" +mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""} platformdirs = ">=2.2" pymdown-extensions = ">=6.3" @@ -1191,4 +1236,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = ">=3.12, <=3.13" -content-hash = "be9872226e6c3cd6d2634629431bcf55322017ff28d186460626e36ff35bae24" +content-hash = "6460c6f6feb20f175eac77d5bff1ca7f6623a7f9756ea0171566aa169e99bafd" diff --git a/pyproject.toml b/pyproject.toml index f0041ad..acd5608 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "python-ntfy" -version = "0.4.2" +version = "0.4.3" description = "An ntfy library aiming for feature completeness" authors = ["Matthew Cane "] readme = "README.md" @@ -17,6 +17,7 @@ classifiers = [ [tool.poetry.dependencies] python = ">=3.12, <=3.13" requests = "^2.31.0" +mkdocstrings = {extras = ["python"], version = "^0.26.2"} [tool.poetry.group.dev.dependencies] mypy = "^1.12.0" @@ -31,6 +32,7 @@ types-pygments = "^2.18.0.20240506" types-colorama = "^0.4.15.20240311" types-requests = "^2.32.0.20241016" types-setuptools = "^75.2.0.20241018" +black = "^24.10.0" [build-system] requires = ["poetry-core"] diff --git a/python_ntfy/_get_functions.py b/python_ntfy/_get_functions.py index 5cc75d9..ab255b8 100644 --- a/python_ntfy/_get_functions.py +++ b/python_ntfy/_get_functions.py @@ -20,10 +20,13 @@ def get_cached_messages( A list of messages. Examples: - response = client.get(since="all") - response = client.get(since="all", scheduled=True) - response = client.get(since="2019-01-01") - response = client.get(since="2019-01-01", scheduled=True) + >>> response = client.get(since="all") + + >>> response = client.get(since="all", scheduled=True) + + >>> response = client.get(since="2019-01-01") + + >>> response = client.get(since="2019-01-01", scheduled=True) """ params = {"poll": "1"} if scheduled: diff --git a/python_ntfy/_send_functions.py b/python_ntfy/_send_functions.py index 16749bd..dcb9481 100644 --- a/python_ntfy/_send_functions.py +++ b/python_ntfy/_send_functions.py @@ -8,7 +8,16 @@ class MessagePriority(Enum): - """Ntfy message priority levels.""" + """Ntfy message priority levels. + + Attributes: + MIN: The minimum priority. + LOW: A low priority. + DEFAULT: The default priority. + HIGH: A high priority. + MAX: The maximum priority. + URGENT: The maximum priority. + """ MIN = "1" LOW = "2" @@ -19,7 +28,13 @@ class MessagePriority(Enum): class ActionType(Enum): - """Action button types.""" + """Action button types. + + Attributes: + VIEW: A view action button. + BROADCAST: A broadcast action button. + HTTP: An HTTP action button. + """ VIEW = "view" BROADCAST = "broadcast" @@ -35,7 +50,19 @@ def __init__(self, label: str, url: str, clear: bool = False) -> None: class ViewAction(Action): + """A view action button. + + The view action opens a website or app when the action button is tapped. + """ + def __init__(self, label: str, url: str, clear: bool = False) -> None: + """Initialize a ViewAction. + + Args: + label: Label of the action button in the notification. + url: URL to open when action is tapped. + clear: Clear notification after action button is tapped. + """ self.action = ActionType.VIEW super().__init__(label=label, url=url, clear=clear) @@ -52,6 +79,11 @@ def to_header(self) -> str: class BroadcastAction(Action): + """A broadcast action button. + + The broadcast action sends an Android broadcast intent when the action button is tapped. + """ + def __init__( self, label: str, @@ -59,6 +91,14 @@ def __init__( extras: Optional[dict[str, str]] = None, clear: bool = False, ) -> None: + """Initialize a BroadcastAction. + + Args: + label: Label of the action button in the notification. + intent: Android intent name. + extras: Android intent extras. + clear: Clear notification after action button is tapped. + """ self.action = ActionType.BROADCAST self.intent = intent self.extras = extras @@ -85,6 +125,11 @@ def to_header(self) -> str: class HttpAction(Action): + """An HTTP action button. + + The http action sends a HTTP request when the action button is tapped. + """ + def __init__( self, label: str, @@ -94,6 +139,16 @@ def __init__( body: Optional[str] = None, clear: bool = False, ) -> None: + """Initialize an HttpAction. + + Args: + label: Label of the action button in the notification. + url: URL to open when action is tapped. + method: HTTP method to use for request. + headers: HTTP headers to send with the request. + body: HTTP body to send with the request. + clear: Clear notification after HTTP request succeeds. If the request fails, the notification is not cleared. + """ self.action = ActionType.HTTP self.method = method self.headers = headers @@ -161,9 +216,11 @@ def send( ToDo Examples: - response = client.send(message="Example message") - response = client.send(message="Example message", title="Example title", priority=MessagePriority.HIGH, tags=["fire", "warning"]) - response = client.send(message="*Example markdown*", format_as_markdown=True) + >>> response = client.send(message="Example message") + + >>> response = client.send(message="Example message", title="Example title", priority=MessagePriority.HIGH, tags=["fire", "warning"]) + + >>> response = client.send(message="*Example markdown*", format_as_markdown=True) """ if tags is None: tags = [] @@ -221,7 +278,7 @@ def send_file( ToDo Examples: - response = client.send_file(file="example.txt") + >>> response = client.send_file(file="example.txt") """ if actions is None: actions = []