stinger-python-utils 0.1.8rc5__tar.gz → 0.1.9__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.
- stinger_python_utils-0.1.9/.github/workflows/python-tests.yml +51 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/.github/workflows/python37.yml +1 -1
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/PKG-INFO +4 -4
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/pyproject.toml +5 -4
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/mcp/server.py +2 -2
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/message_creator.py +17 -0
- stinger_python_utils-0.1.9/uv.lock +2052 -0
- stinger_python_utils-0.1.8rc5/.github/workflows/python-tests.yml +0 -29
- stinger_python_utils-0.1.8rc5/.python-version +0 -4
- stinger_python_utils-0.1.8rc5/uv.lock +0 -868
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/.gitignore +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/.vscode/settings.json +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/LICENSE +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/README.md +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/__init__.py +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/mcp/__init__.py +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/mcp/__main__.py +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/mcp/plugin.py +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/return_codes.py +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/test/__init__.py +0 -0
- {stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/test/test_message_creator.py +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Python Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
# Python 3.7 requires a completely different setup because it is very EOL.
|
|
15
|
+
include:
|
|
16
|
+
- python-version: "3.10"
|
|
17
|
+
uv-sync-flags: "--all-extras"
|
|
18
|
+
mypy-flags: "--exclude '/mcp/'"
|
|
19
|
+
- python-version: "3.11"
|
|
20
|
+
uv-sync-flags: "--all-extras"
|
|
21
|
+
mypy-flags: ""
|
|
22
|
+
- python-version: "3.12"
|
|
23
|
+
uv-sync-flags: "--all-extras"
|
|
24
|
+
mypy-flags: ""
|
|
25
|
+
- python-version: "3.13"
|
|
26
|
+
uv-sync-flags: "--all-extras"
|
|
27
|
+
mypy-flags: ""
|
|
28
|
+
- python-version: "3.14"
|
|
29
|
+
uv-sync-flags: "--all-extras"
|
|
30
|
+
mypy-flags: ""
|
|
31
|
+
- python-version: "3.8"
|
|
32
|
+
uv-sync-flags: ""
|
|
33
|
+
mypy-flags: "--exclude '/mcp/'"
|
|
34
|
+
- python-version: "3.9"
|
|
35
|
+
uv-sync-flags: ""
|
|
36
|
+
mypy-flags: "--exclude '/mcp/'"
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
- name: Install UV
|
|
40
|
+
uses: astral-sh/setup-uv@v7
|
|
41
|
+
with:
|
|
42
|
+
python-version: ${{ matrix.python-version }}
|
|
43
|
+
- name: Install project
|
|
44
|
+
run: |
|
|
45
|
+
uv sync --locked ${{ matrix.uv-sync-flags }} --dev
|
|
46
|
+
- name: Run unit tests
|
|
47
|
+
run: |
|
|
48
|
+
uv run pytest
|
|
49
|
+
- name: Mypy Type Check
|
|
50
|
+
run: |
|
|
51
|
+
uv run mypy --check-untyped-defs ${{ matrix.mypy-flags }} ./src/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stinger-python-utils
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.9
|
|
4
4
|
Summary: Common utilities for Stinger Python services.
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,9 +8,9 @@ Requires-Python: >=3.7
|
|
|
8
8
|
Requires-Dist: pydantic>=2.5.3
|
|
9
9
|
Requires-Dist: pyqttier>=0.2.0
|
|
10
10
|
Provides-Extra: mcp
|
|
11
|
-
Requires-Dist: mcp>=1.
|
|
12
|
-
Requires-Dist: stevedore>=5.
|
|
13
|
-
Requires-Dist: uvicorn>=0.
|
|
11
|
+
Requires-Dist: mcp>=1.27.0; (python_version >= '3.10') and extra == 'mcp'
|
|
12
|
+
Requires-Dist: stevedore>=5.7; (python_version >= '3.10') and extra == 'mcp'
|
|
13
|
+
Requires-Dist: uvicorn>=0.44.0; (python_version >= '3.10') and extra == 'mcp'
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
|
|
16
16
|
# stinger-python-utils
|
|
@@ -4,11 +4,12 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "stinger-python-utils"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.9"
|
|
8
8
|
description = "Common utilities for Stinger Python services."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
requires-python = ">=3.7"
|
|
12
|
+
|
|
12
13
|
dependencies = [
|
|
13
14
|
"pydantic>=2.5.3",
|
|
14
15
|
"pyqttier>=0.2.0",
|
|
@@ -16,9 +17,9 @@ dependencies = [
|
|
|
16
17
|
|
|
17
18
|
[project.optional-dependencies]
|
|
18
19
|
mcp = [
|
|
19
|
-
"mcp>=1.0.
|
|
20
|
-
"stevedore>=5.
|
|
21
|
-
"uvicorn>=0.
|
|
20
|
+
"mcp>=1.27.0; python_version >= '3.10'",
|
|
21
|
+
"stevedore>=5.7; python_version >= '3.10'",
|
|
22
|
+
"uvicorn>=0.44.0; python_version >= '3.10'",
|
|
22
23
|
]
|
|
23
24
|
|
|
24
25
|
[project.scripts]
|
{stinger_python_utils-0.1.8rc5 → stinger_python_utils-0.1.9}/src/stinger_python_utils/mcp/server.py
RENAMED
|
@@ -377,11 +377,11 @@ class StingerMCPServer:
|
|
|
377
377
|
|
|
378
378
|
def _load_plugins(self) -> None:
|
|
379
379
|
def _on_failure(
|
|
380
|
-
_mgr:
|
|
380
|
+
_mgr: Any, entrypoint: Any, err: BaseException
|
|
381
381
|
) -> None:
|
|
382
382
|
logger.error("Failed to load plugin %s: %s", entrypoint, err)
|
|
383
383
|
|
|
384
|
-
mgr = ExtensionManager(
|
|
384
|
+
mgr: ExtensionManager[Any] = ExtensionManager(
|
|
385
385
|
namespace=self.STEVEDORE_NAMESPACE,
|
|
386
386
|
invoke_on_load=True,
|
|
387
387
|
on_load_failure_callback=_on_failure,
|
|
@@ -7,8 +7,16 @@ from .return_codes import MethodReturnCode
|
|
|
7
7
|
|
|
8
8
|
class MessageCreator:
|
|
9
9
|
|
|
10
|
+
@staticmethod
|
|
11
|
+
def _validate_topic(topic: str, param_name: str = "topic") -> None:
|
|
12
|
+
if "+" in topic:
|
|
13
|
+
raise ValueError(
|
|
14
|
+
f"{param_name} must not contain '+', got: {topic!r}"
|
|
15
|
+
)
|
|
16
|
+
|
|
10
17
|
@classmethod
|
|
11
18
|
def signal_message(cls, topic: str, payload: BaseModel) -> Message:
|
|
19
|
+
cls._validate_topic(topic)
|
|
12
20
|
return Message(
|
|
13
21
|
topic=topic,
|
|
14
22
|
payload=payload.model_dump_json(by_alias=True).encode("utf-8"),
|
|
@@ -21,6 +29,7 @@ class MessageCreator:
|
|
|
21
29
|
def status_message(
|
|
22
30
|
cls, topic, status_message: BaseModel, expiry_seconds: int
|
|
23
31
|
) -> Message:
|
|
32
|
+
cls._validate_topic(topic)
|
|
24
33
|
return Message(
|
|
25
34
|
topic=topic,
|
|
26
35
|
payload=status_message.model_dump_json(by_alias=True).encode("utf-8"),
|
|
@@ -41,6 +50,7 @@ class MessageCreator:
|
|
|
41
50
|
"""
|
|
42
51
|
This could be used for a response to a request, but where there was an error fulfilling the request.
|
|
43
52
|
"""
|
|
53
|
+
cls._validate_topic(topic)
|
|
44
54
|
rc = (
|
|
45
55
|
return_code.value
|
|
46
56
|
if isinstance(return_code, MethodReturnCode)
|
|
@@ -76,6 +86,7 @@ class MessageCreator:
|
|
|
76
86
|
"""
|
|
77
87
|
This could be used for a successful response to a request.
|
|
78
88
|
"""
|
|
89
|
+
cls._validate_topic(response_topic, "response_topic")
|
|
79
90
|
if isinstance(response_obj, BaseModel):
|
|
80
91
|
payload = response_obj.model_dump_json(by_alias=True).encode("utf-8")
|
|
81
92
|
elif isinstance(response_obj, str):
|
|
@@ -109,6 +120,7 @@ class MessageCreator:
|
|
|
109
120
|
"""
|
|
110
121
|
Creates a retained message representing the state/value of a property.
|
|
111
122
|
"""
|
|
123
|
+
cls._validate_topic(topic)
|
|
112
124
|
msg_obj = Message(
|
|
113
125
|
topic=topic,
|
|
114
126
|
payload=state_obj.model_dump_json(by_alias=True).encode("utf-8"),
|
|
@@ -132,6 +144,8 @@ class MessageCreator:
|
|
|
132
144
|
"""
|
|
133
145
|
Creates a message representing a request to update a property.
|
|
134
146
|
"""
|
|
147
|
+
cls._validate_topic(topic)
|
|
148
|
+
cls._validate_topic(response_topic, "response_topic")
|
|
135
149
|
msg_obj = Message(
|
|
136
150
|
topic=topic,
|
|
137
151
|
payload=property_obj.model_dump_json(by_alias=True).encode("utf-8"),
|
|
@@ -161,6 +175,7 @@ class MessageCreator:
|
|
|
161
175
|
"""
|
|
162
176
|
Creates a message representing a response to a property update request.
|
|
163
177
|
"""
|
|
178
|
+
cls._validate_topic(response_topic, "response_topic")
|
|
164
179
|
rc = (
|
|
165
180
|
return_code.value
|
|
166
181
|
if isinstance(return_code, MethodReturnCode)
|
|
@@ -196,6 +211,8 @@ class MessageCreator:
|
|
|
196
211
|
response_topic: str,
|
|
197
212
|
correlation_id: Union[str, bytes, None] = None,
|
|
198
213
|
) -> Message:
|
|
214
|
+
cls._validate_topic(topic)
|
|
215
|
+
cls._validate_topic(response_topic, "response_topic")
|
|
199
216
|
if correlation_id is None:
|
|
200
217
|
correlation_id = str(uuid.uuid4())
|
|
201
218
|
msg_obj = Message(
|