utcp-socket 1.0.2__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.
- utcp_socket-1.0.2/PKG-INFO +69 -0
- utcp_socket-1.0.2/README.md +44 -0
- utcp_socket-1.0.2/pyproject.toml +42 -0
- utcp_socket-1.0.2/setup.cfg +4 -0
- utcp_socket-1.0.2/src/utcp_socket/__init__.py +18 -0
- utcp_socket-1.0.2/src/utcp_socket/tcp_call_template.py +99 -0
- utcp_socket-1.0.2/src/utcp_socket/tcp_communication_protocol.py +434 -0
- utcp_socket-1.0.2/src/utcp_socket/udp_call_template.py +56 -0
- utcp_socket-1.0.2/src/utcp_socket/udp_communication_protocol.py +337 -0
- utcp_socket-1.0.2/src/utcp_socket.egg-info/PKG-INFO +69 -0
- utcp_socket-1.0.2/src/utcp_socket.egg-info/SOURCES.txt +15 -0
- utcp_socket-1.0.2/src/utcp_socket.egg-info/dependency_links.txt +1 -0
- utcp_socket-1.0.2/src/utcp_socket.egg-info/entry_points.txt +2 -0
- utcp_socket-1.0.2/src/utcp_socket.egg-info/requires.txt +10 -0
- utcp_socket-1.0.2/src/utcp_socket.egg-info/top_level.txt +1 -0
- utcp_socket-1.0.2/tests/test_tcp_communication_protocol.py +180 -0
- utcp_socket-1.0.2/tests/test_udp_communication_protocol.py +176 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: utcp-socket
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: UTCP communication protocol plugin for TCP and UDP protocols. (Work in progress)
|
|
5
|
+
Author: UTCP Contributors
|
|
6
|
+
License-Expression: MPL-2.0
|
|
7
|
+
Project-URL: Homepage, https://utcp.io
|
|
8
|
+
Project-URL: Source, https://github.com/universal-tool-calling-protocol/python-utcp
|
|
9
|
+
Project-URL: Issues, https://github.com/universal-tool-calling-protocol/python-utcp/issues
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
Requires-Dist: pydantic>=2.0
|
|
17
|
+
Requires-Dist: utcp>=1.0
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
Requires-Dist: build; extra == "dev"
|
|
20
|
+
Requires-Dist: pytest; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
23
|
+
Requires-Dist: coverage; extra == "dev"
|
|
24
|
+
Requires-Dist: twine; extra == "dev"
|
|
25
|
+
|
|
26
|
+
# UTCP Socket Plugin (UDP/TCP)
|
|
27
|
+
|
|
28
|
+
This plugin adds UDP and TCP communication protocols to UTCP 1.0.
|
|
29
|
+
|
|
30
|
+
## Running Tests
|
|
31
|
+
|
|
32
|
+
Prerequisites:
|
|
33
|
+
- Python 3.10+
|
|
34
|
+
- `pip`
|
|
35
|
+
- (Optional) a virtual environment
|
|
36
|
+
|
|
37
|
+
1) Install core and the socket plugin in editable mode with dev extras:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e "./core[dev]"
|
|
41
|
+
pip install -e ./plugins/communication_protocols/socket[dev]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
2) Run the socket plugin tests:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
python -m pytest plugins/communication_protocols/socket/tests -v
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
3) Run a single test or filter by keyword:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# One file
|
|
54
|
+
python -m pytest plugins/communication_protocols/socket/tests/test_tcp_communication_protocol.py -v
|
|
55
|
+
|
|
56
|
+
# Filter by keyword (e.g., delimiter framing)
|
|
57
|
+
python -m pytest plugins/communication_protocols/socket/tests -k delimiter -q
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
4) Optional end-to-end sanity check (mock UDP/TCP servers):
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python scripts/socket_sanity.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Notes:
|
|
67
|
+
- On Windows, your firewall may prompt the first time tests open UDP/TCP sockets; allow access or run as admin if needed.
|
|
68
|
+
- Tests use `pytest-asyncio`. The dev extras installed above provide required dependencies.
|
|
69
|
+
- Streaming is single-chunk by design, consistent with HTTP/Text transports. Multi-chunk streaming can be added later behind provider configuration.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# UTCP Socket Plugin (UDP/TCP)
|
|
2
|
+
|
|
3
|
+
This plugin adds UDP and TCP communication protocols to UTCP 1.0.
|
|
4
|
+
|
|
5
|
+
## Running Tests
|
|
6
|
+
|
|
7
|
+
Prerequisites:
|
|
8
|
+
- Python 3.10+
|
|
9
|
+
- `pip`
|
|
10
|
+
- (Optional) a virtual environment
|
|
11
|
+
|
|
12
|
+
1) Install core and the socket plugin in editable mode with dev extras:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install -e "./core[dev]"
|
|
16
|
+
pip install -e ./plugins/communication_protocols/socket[dev]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2) Run the socket plugin tests:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m pytest plugins/communication_protocols/socket/tests -v
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3) Run a single test or filter by keyword:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# One file
|
|
29
|
+
python -m pytest plugins/communication_protocols/socket/tests/test_tcp_communication_protocol.py -v
|
|
30
|
+
|
|
31
|
+
# Filter by keyword (e.g., delimiter framing)
|
|
32
|
+
python -m pytest plugins/communication_protocols/socket/tests -k delimiter -q
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
4) Optional end-to-end sanity check (mock UDP/TCP servers):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python scripts/socket_sanity.py
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Notes:
|
|
42
|
+
- On Windows, your firewall may prompt the first time tests open UDP/TCP sockets; allow access or run as admin if needed.
|
|
43
|
+
- Tests use `pytest-asyncio`. The dev extras installed above provide required dependencies.
|
|
44
|
+
- Streaming is single-chunk by design, consistent with HTTP/Text transports. Multi-chunk streaming can be added later behind provider configuration.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "utcp-socket"
|
|
7
|
+
version = "1.0.2"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "UTCP Contributors" },
|
|
10
|
+
]
|
|
11
|
+
description = "UTCP communication protocol plugin for TCP and UDP protocols. (Work in progress)"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
dependencies = [
|
|
15
|
+
"pydantic>=2.0",
|
|
16
|
+
"utcp>=1.0"
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Operating System :: OS Independent",
|
|
23
|
+
]
|
|
24
|
+
license = "MPL-2.0"
|
|
25
|
+
|
|
26
|
+
[project.optional-dependencies]
|
|
27
|
+
dev = [
|
|
28
|
+
"build",
|
|
29
|
+
"pytest",
|
|
30
|
+
"pytest-asyncio",
|
|
31
|
+
"pytest-cov",
|
|
32
|
+
"coverage",
|
|
33
|
+
"twine",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://utcp.io"
|
|
38
|
+
Source = "https://github.com/universal-tool-calling-protocol/python-utcp"
|
|
39
|
+
Issues = "https://github.com/universal-tool-calling-protocol/python-utcp/issues"
|
|
40
|
+
|
|
41
|
+
[project.entry-points."utcp.plugins"]
|
|
42
|
+
socket = "utcp_socket:register"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from utcp.plugins.discovery import register_communication_protocol, register_call_template
|
|
2
|
+
from utcp_socket.tcp_communication_protocol import TCPTransport
|
|
3
|
+
from utcp_socket.udp_communication_protocol import UDPTransport
|
|
4
|
+
from utcp_socket.tcp_call_template import TCPProviderSerializer
|
|
5
|
+
from utcp_socket.udp_call_template import UDPProviderSerializer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register() -> None:
|
|
9
|
+
# Register communication protocols
|
|
10
|
+
register_communication_protocol("tcp", TCPTransport())
|
|
11
|
+
register_communication_protocol("udp", UDPTransport())
|
|
12
|
+
|
|
13
|
+
# Register call templates and their serializers
|
|
14
|
+
register_call_template("tcp", TCPProviderSerializer())
|
|
15
|
+
register_call_template("udp", UDPProviderSerializer())
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["register"]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from utcp.data.call_template import CallTemplate
|
|
2
|
+
from typing import Optional, Literal
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
from utcp.interfaces.serializer import Serializer
|
|
5
|
+
from utcp.exceptions import UtcpSerializerValidationError
|
|
6
|
+
import traceback
|
|
7
|
+
|
|
8
|
+
class TCPProvider(CallTemplate):
|
|
9
|
+
"""Provider configuration for raw TCP socket tools.
|
|
10
|
+
|
|
11
|
+
Enables direct communication with TCP servers using custom protocols.
|
|
12
|
+
Supports flexible request formatting, response decoding, and multiple
|
|
13
|
+
framing strategies for message boundaries.
|
|
14
|
+
|
|
15
|
+
Request Data Handling:
|
|
16
|
+
- 'json' format: Arguments formatted as JSON object
|
|
17
|
+
- 'text' format: Template-based with UTCP_ARG_argname_UTCP_ARG placeholders
|
|
18
|
+
|
|
19
|
+
Response Data Handling:
|
|
20
|
+
- If response_byte_format is None: Returns raw bytes
|
|
21
|
+
- If response_byte_format is encoding string: Decodes bytes to text
|
|
22
|
+
|
|
23
|
+
TCP Stream Framing Options:
|
|
24
|
+
1. Length-prefix: Set framing_strategy='length_prefix' + length_prefix_bytes
|
|
25
|
+
2. Delimiter-based: Set framing_strategy='delimiter' + message_delimiter
|
|
26
|
+
3. Fixed-length: Set framing_strategy='fixed_length' + fixed_message_length
|
|
27
|
+
4. Stream-based: Set framing_strategy='stream' (reads until connection closes)
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
call_template_type: Always "tcp" for TCP providers.
|
|
31
|
+
host: The hostname or IP address of the TCP server.
|
|
32
|
+
port: The port number of the TCP server.
|
|
33
|
+
request_data_format: Format for request data ('json' or 'text').
|
|
34
|
+
request_data_template: Template string for 'text' format with placeholders.
|
|
35
|
+
response_byte_format: Encoding for response decoding (None for raw bytes).
|
|
36
|
+
framing_strategy: Method for detecting message boundaries.
|
|
37
|
+
length_prefix_bytes: Number of bytes for length prefix (1, 2, 4, or 8).
|
|
38
|
+
length_prefix_endian: Byte order for length prefix ('big' or 'little').
|
|
39
|
+
message_delimiter: Delimiter string for message boundaries.
|
|
40
|
+
fixed_message_length: Fixed length in bytes for each message.
|
|
41
|
+
max_response_size: Maximum bytes to read for stream-based framing.
|
|
42
|
+
timeout: Connection timeout in milliseconds.
|
|
43
|
+
auth: Always None - TCP providers don't support authentication.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
call_template_type: Literal["tcp"] = "tcp"
|
|
47
|
+
host: str
|
|
48
|
+
port: int
|
|
49
|
+
request_data_format: Literal["json", "text"] = "json"
|
|
50
|
+
request_data_template: Optional[str] = None
|
|
51
|
+
response_byte_format: Optional[str] = Field(default="utf-8", description="Encoding to decode response bytes. If None, returns raw bytes.")
|
|
52
|
+
# TCP Framing Strategy
|
|
53
|
+
framing_strategy: Literal["length_prefix", "delimiter", "fixed_length", "stream"] = Field(
|
|
54
|
+
default="stream",
|
|
55
|
+
description="Strategy for framing TCP messages"
|
|
56
|
+
)
|
|
57
|
+
# Length-prefix framing options
|
|
58
|
+
length_prefix_bytes: Literal[1, 2, 4, 8] = Field(
|
|
59
|
+
default=4,
|
|
60
|
+
description="Number of bytes for length prefix (1, 2, 4, or 8). Used with 'length_prefix' framing."
|
|
61
|
+
)
|
|
62
|
+
length_prefix_endian: Literal["big", "little"] = Field(
|
|
63
|
+
default="big",
|
|
64
|
+
description="Byte order for length prefix. Used with 'length_prefix' framing."
|
|
65
|
+
)
|
|
66
|
+
# Delimiter-based framing options
|
|
67
|
+
message_delimiter: str = Field(
|
|
68
|
+
default='\x00',
|
|
69
|
+
description="Delimiter to detect end of TCP response (e.g., '\n', '\r\n', '\x00'). Used with 'delimiter' framing."
|
|
70
|
+
)
|
|
71
|
+
interpret_escape_sequences: bool = Field(
|
|
72
|
+
default=True,
|
|
73
|
+
description="If True, interpret Python-style escape sequences in message_delimiter (e.g., '\\n', '\\r\\n', '\\x00'). If False, use the delimiter literally as provided."
|
|
74
|
+
)
|
|
75
|
+
# Fixed-length framing options
|
|
76
|
+
fixed_message_length: Optional[int] = Field(
|
|
77
|
+
default=None,
|
|
78
|
+
description="Fixed length of each message in bytes. Used with 'fixed_length' framing."
|
|
79
|
+
)
|
|
80
|
+
# Stream-based options
|
|
81
|
+
max_response_size: int = Field(
|
|
82
|
+
default=65536,
|
|
83
|
+
description="Maximum bytes to read from TCP stream. Used with 'stream' framing."
|
|
84
|
+
)
|
|
85
|
+
timeout: int = 30000
|
|
86
|
+
auth: None = None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class TCPProviderSerializer(Serializer[TCPProvider]):
|
|
90
|
+
def to_dict(self, obj: TCPProvider) -> dict:
|
|
91
|
+
return obj.model_dump()
|
|
92
|
+
|
|
93
|
+
def validate_dict(self, data: dict) -> TCPProvider:
|
|
94
|
+
try:
|
|
95
|
+
return TCPProvider.model_validate(data)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
raise UtcpSerializerValidationError(
|
|
98
|
+
f"Invalid TCPProvider: {e}\n{traceback.format_exc()}"
|
|
99
|
+
)
|