python-ntfy 0.8.0__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-ntfy
3
- Version: 0.8.0
3
+ Version: 0.9.0
4
4
  Summary: An ntfy library aiming for feature completeness
5
5
  Keywords: ntfy,notifications,push,http,api
6
6
  Author: Matthew Cane
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
43
43
  # A Python Library For ntfy
44
44
 
45
45
  ![GitHub Release](https://img.shields.io/github/v/release/MatthewCane/python-ntfy?display_name=release&label=latest%20release&link=https%3A%2F%2Fgithub.com%2FMatthewCane%2Fpython-ntfy%2Freleases%2Flatest)
46
- ![PyPI - Downloads](https://img.shields.io/pypi/dm/python-ntfy?logo=pypi&link=http%3A%2F%2Fpypi.org%2Fproject%2Fpython-ntfy%2F)
46
+ [![PyPI Downloads](https://static.pepy.tech/badge/python-ntfy/month)](https://pepy.tech/projects/python-ntfy)
47
47
  ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/MatthewCane/python-ntfy/publish.yml?logo=githubactions&link=https%3A%2F%2Fgithub.com%2FMatthewCane%2Fpython-ntfy%2Factions%2Fworkflows%2Fpublish.yml)
48
48
 
49
49
  An easy-to-use python library for the [ntfy notification service](https://ntfy.sh/). Aiming for full feature support and a super easy to use interface.
@@ -1,7 +1,7 @@
1
1
  # A Python Library For ntfy
2
2
 
3
3
  ![GitHub Release](https://img.shields.io/github/v/release/MatthewCane/python-ntfy?display_name=release&label=latest%20release&link=https%3A%2F%2Fgithub.com%2FMatthewCane%2Fpython-ntfy%2Freleases%2Flatest)
4
- ![PyPI - Downloads](https://img.shields.io/pypi/dm/python-ntfy?logo=pypi&link=http%3A%2F%2Fpypi.org%2Fproject%2Fpython-ntfy%2F)
4
+ [![PyPI Downloads](https://static.pepy.tech/badge/python-ntfy/month)](https://pepy.tech/projects/python-ntfy)
5
5
  ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/MatthewCane/python-ntfy/publish.yml?logo=githubactions&link=https%3A%2F%2Fgithub.com%2FMatthewCane%2Fpython-ntfy%2Factions%2Fworkflows%2Fpublish.yml)
6
6
 
7
7
  An easy-to-use python library for the [ntfy notification service](https://ntfy.sh/). Aiming for full feature support and a super easy to use interface.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-ntfy"
3
- version = "0.8.0"
3
+ version = "0.9.0"
4
4
  description = "An ntfy library aiming for feature completeness"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -74,6 +74,9 @@ dev = [
74
74
  [tool.ruff]
75
75
  target-version = "py312"
76
76
 
77
+ [tool.ruff.lint.isort]
78
+ combine-as-imports = true
79
+
77
80
  [tool.ruff.lint]
78
81
  select = [
79
82
  "E", # PycodeStyle errors
@@ -125,3 +128,23 @@ addopts = [
125
128
  "--cov-fail-under=95",
126
129
  "--cov-report=term-missing",
127
130
  ]
131
+
132
+ [tool.mypy]
133
+ python_version = "3.12"
134
+ warn_unused_ignores = true
135
+ warn_redundant_casts = true
136
+ warn_unreachable = true
137
+ no_implicit_optional = true
138
+ strict_equality = true
139
+ pretty = true
140
+ # Default expectations for the codebase; public modules may override to be stricter.
141
+ disallow_incomplete_defs = false
142
+ disallow_untyped_defs = false
143
+
144
+ [[tool.mypy.overrides]]
145
+ module = [
146
+ "python_ntfy.client",
147
+ "python_ntfy.__init__",
148
+ ]
149
+ disallow_incomplete_defs = true
150
+ disallow_untyped_defs = true
@@ -0,0 +1,17 @@
1
+ from ._exceptions import MessageSendError as MessageSendError
2
+ from ._send_functions import (
3
+ BroadcastAction as BroadcastAction,
4
+ HttpAction as HttpAction,
5
+ MessagePriority as MessagePriority,
6
+ ViewAction as ViewAction,
7
+ )
8
+ from .client import NtfyClient as NtfyClient
9
+
10
+ __all__ = [
11
+ "BroadcastAction",
12
+ "HttpAction",
13
+ "MessagePriority",
14
+ "MessageSendError",
15
+ "NtfyClient",
16
+ "ViewAction",
17
+ ]
@@ -0,0 +1,19 @@
1
+ """Compatibility shim for historical import path.
2
+
3
+ Prefer importing from `python_ntfy` package root:
4
+
5
+ from python_ntfy import NtfyClient
6
+
7
+ This module re-exports `NtfyClient` to maintain backward compatibility with
8
+ older references like `python_ntfy._ntfy.NtfyClient`.
9
+ """
10
+
11
+ from warnings import warn
12
+
13
+ from .client import NtfyClient as NtfyClient
14
+
15
+ warn(
16
+ "`python_ntfy._ntfy` is deprecated and will be removed in a future version. Please import from `python_ntfy` instead.",
17
+ DeprecationWarning,
18
+ stacklevel=2,
19
+ )
@@ -0,0 +1,146 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+
7
+ from ._get_functions import get_cached_messages as _get_cached_messages
8
+ from ._send_functions import (
9
+ BroadcastAction as _BroadcastAction,
10
+ HttpAction as _HttpAction,
11
+ MessagePriority as _MessagePriority,
12
+ ViewAction as _ViewAction,
13
+ send as _send_message,
14
+ send_file as _send_file,
15
+ )
16
+
17
+
18
+ class NtfyClient:
19
+ """A client for interacting with the ntfy notification service."""
20
+
21
+ # Backwards-compatible attribute exposure (discouraged for new code):
22
+ BroadcastAction = _BroadcastAction
23
+ HttpAction = _HttpAction
24
+ MessagePriority = _MessagePriority
25
+ ViewAction = _ViewAction
26
+
27
+ def __init__(
28
+ self,
29
+ topic: str,
30
+ server: str = "https://ntfy.sh",
31
+ auth: tuple[str, str] | str | None = None,
32
+ ) -> None:
33
+ """Initialize the client.
34
+
35
+ Args:
36
+ topic: The topic to use for this client.
37
+ server: The server base URL (must include protocol, e.g., https://).
38
+ auth: Credentials for this client. Takes precedence over environment
39
+ variables. May be a tuple ``(user, password)`` for Basic auth
40
+ or a token string for Bearer auth.
41
+ """
42
+ self._server = os.environ.get("NTFY_SERVER") or server
43
+ self._topic = topic
44
+ self.__set_url(self._server, topic)
45
+ self._auth: tuple[str, str] | None = self._resolve_auth(auth)
46
+
47
+ def _resolve_auth(
48
+ self, auth: tuple[str, str] | str | None
49
+ ) -> tuple[str, str] | None:
50
+ """Resolve authentication credentials using args or environment variables."""
51
+ # Explicitly provided credentials take precedence (including empty string)
52
+ if auth is not None:
53
+ if isinstance(auth, tuple):
54
+ return auth
55
+ if isinstance(auth, str):
56
+ return ("", auth)
57
+
58
+ # Fallback to environment variables
59
+ user = os.environ.get("NTFY_USER")
60
+ password = os.environ.get("NTFY_PASSWORD")
61
+ token = os.environ.get("NTFY_TOKEN")
62
+
63
+ if user and password:
64
+ return (user, password)
65
+ if token:
66
+ return ("", token)
67
+
68
+ return None
69
+
70
+ def __set_url(self, server: str, topic: str) -> None:
71
+ self.url = server.strip("/") + "/" + topic
72
+
73
+ def set_topic(self, topic: str) -> None:
74
+ """Set a new topic for this client."""
75
+ self._topic = topic
76
+ self.__set_url(self._server, self._topic)
77
+
78
+ def get_topic(self) -> str:
79
+ """Get the current topic."""
80
+ return self._topic
81
+
82
+ # Public API methods delegate to internal helpers for implementation
83
+
84
+ def send(
85
+ self,
86
+ message: str,
87
+ title: str | None = None,
88
+ priority: _MessagePriority = _MessagePriority.DEFAULT,
89
+ tags: list[str] | None = None,
90
+ actions: list[_ViewAction | _BroadcastAction | _HttpAction] | None = None,
91
+ schedule: datetime | None = None,
92
+ format_as_markdown: bool = False,
93
+ timeout_seconds: int = 5,
94
+ email: str | None = None,
95
+ ) -> dict:
96
+ """Send a text-based message to the server."""
97
+ return _send_message(
98
+ self,
99
+ message=message,
100
+ title=title,
101
+ priority=priority,
102
+ tags=tags,
103
+ actions=actions,
104
+ schedule=schedule,
105
+ format_as_markdown=format_as_markdown,
106
+ timeout_seconds=timeout_seconds,
107
+ email=email,
108
+ )
109
+
110
+ def send_file(
111
+ self,
112
+ file: str | Path,
113
+ title: str | None = None,
114
+ priority: _MessagePriority = _MessagePriority.DEFAULT,
115
+ tags: list[str] | None = None,
116
+ actions: list[_ViewAction | _BroadcastAction | _HttpAction] | None = None,
117
+ schedule: datetime | None = None,
118
+ timeout_seconds: int = 30,
119
+ email: str | None = None,
120
+ ) -> dict:
121
+ """Send a file to the server."""
122
+ return _send_file(
123
+ self,
124
+ file=file,
125
+ title=title,
126
+ priority=priority,
127
+ tags=tags,
128
+ actions=actions,
129
+ schedule=schedule,
130
+ timeout_seconds=timeout_seconds,
131
+ email=email,
132
+ )
133
+
134
+ def get_cached_messages(
135
+ self,
136
+ since: str = "all",
137
+ scheduled: bool = False,
138
+ timeout_seconds: int = 10,
139
+ ) -> list[dict]:
140
+ """Get cached messages from the server."""
141
+ return _get_cached_messages(
142
+ self,
143
+ since=since,
144
+ scheduled=scheduled,
145
+ timeout_seconds=timeout_seconds,
146
+ )
File without changes
@@ -1,3 +0,0 @@
1
- from ._ntfy import NtfyClient as NtfyClient
2
-
3
- __all__ = ["NtfyClient"]
@@ -1,134 +0,0 @@
1
- """This module provides the NtfyClient class for interacting with the ntfy notification service.
2
-
3
- The NtfyClient class allows users to send notifications, files, and perform various actions
4
- through the ntfy.sh service. It also supports retrieving cached messages.
5
-
6
- Typical usage example:
7
-
8
- client = NtfyClient(topic="my_topic")
9
- client.send("Hello, World!")
10
- """
11
-
12
- import os
13
-
14
- from ._get_functions import get_cached_messages
15
- from ._send_functions import (
16
- BroadcastAction,
17
- HttpAction,
18
- MessagePriority,
19
- ViewAction,
20
- send,
21
- send_file,
22
- )
23
-
24
-
25
- class GetFunctionsMixin:
26
- """Mixin for getting messages."""
27
-
28
- get_cached_messages = get_cached_messages
29
-
30
-
31
- class SendFunctionsMixin:
32
- """Mixin for sending messages."""
33
-
34
- send = send
35
- send_file = send_file
36
- BroadcastAction = BroadcastAction
37
- HttpAction = HttpAction
38
- MessagePriority = MessagePriority
39
- ViewAction = ViewAction
40
-
41
-
42
- class NtfyClient(GetFunctionsMixin, SendFunctionsMixin):
43
- """A class for interacting with the ntfy notification service."""
44
-
45
- def __init__(
46
- self,
47
- topic: str,
48
- server: str = "https://ntfy.sh",
49
- auth: tuple[str, str] | str | None = None,
50
- ) -> None:
51
- """Itinialize the NtfyClient.
52
-
53
- Args:
54
- topic: The topic to use for this client
55
- server: The server to connect to. Must include the protocol (http/https)
56
- auth: The authentication credentials to use for this client. Takes precedence over environment variables. Can be a tuple of (user, password) or a token.
57
-
58
- Returns:
59
- None
60
-
61
- Exceptions:
62
- None
63
-
64
- Examples:
65
- client = NtfyClient(topic="my_topic")
66
- """
67
- self._server = os.environ.get("NTFY_SERVER") or server
68
- self._topic = topic
69
- self.__set_url(self._server, topic)
70
- self._auth: tuple[str, str] | None = self._resolve_auth(auth)
71
-
72
- def _resolve_auth(
73
- self, auth: tuple[str, str] | str | None
74
- ) -> tuple[str, str] | None:
75
- """Resolve the authentication credentials.
76
-
77
- Args:
78
- auth: The authentication credentials to use for this client. Takes precedence over environment variables. Can be a tuple of (user, password) or a token string.
79
-
80
- Returns:
81
- tuple[str, str] | None: The authentication credentials.
82
- """
83
- # If the user has supplied credentials, use them (including empty string)
84
- if auth is not None:
85
- if isinstance(auth, tuple):
86
- return auth
87
- if isinstance(auth, str):
88
- return ("", auth)
89
-
90
- # Otherwise, check environment variables
91
- user = os.environ.get("NTFY_USER")
92
- password = os.environ.get("NTFY_PASSWORD")
93
- token = os.environ.get("NTFY_TOKEN")
94
-
95
- if user and password:
96
- return (user, password)
97
-
98
- if token:
99
- return ("", token)
100
-
101
- # If no credentials are found, return None
102
- return None
103
-
104
- def __set_url(
105
- self,
106
- server,
107
- topic,
108
- ) -> None:
109
- self.url = server.strip("/") + "/" + topic
110
-
111
- def set_topic(
112
- self,
113
- topic: str,
114
- ) -> None:
115
- """Set a new topic for the client.
116
-
117
- Args:
118
- topic: The topic to set for this client.
119
-
120
- Returns:
121
- None
122
- """
123
- self._topic = topic
124
- self.__set_url(self._server, self._topic)
125
-
126
- def get_topic(
127
- self,
128
- ) -> str:
129
- """Get the current topic.
130
-
131
- Returns:
132
- str: The current topic.
133
- """
134
- return self._topic