moat-lib-proxy 0.1.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.
- moat_lib_proxy-0.1.0/LICENSE.txt +14 -0
- moat_lib_proxy-0.1.0/Makefile +14 -0
- moat_lib_proxy-0.1.0/PKG-INFO +118 -0
- moat_lib_proxy-0.1.0/README.md +96 -0
- moat_lib_proxy-0.1.0/debian/.gitignore +7 -0
- moat_lib_proxy-0.1.0/debian/changelog +29 -0
- moat_lib_proxy-0.1.0/debian/control +20 -0
- moat_lib_proxy-0.1.0/debian/rules +5 -0
- moat_lib_proxy-0.1.0/pyproject.toml +36 -0
- moat_lib_proxy-0.1.0/setup.cfg +4 -0
- moat_lib_proxy-0.1.0/src/moat/lib/proxy/__init__.py +31 -0
- moat_lib_proxy-0.1.0/src/moat/lib/proxy/_impl.py +155 -0
- moat_lib_proxy-0.1.0/src/moat/lib/proxy/_proxy.py +196 -0
- moat_lib_proxy-0.1.0/src/moat_lib_proxy.egg-info/PKG-INFO +118 -0
- moat_lib_proxy-0.1.0/src/moat_lib_proxy.egg-info/SOURCES.txt +16 -0
- moat_lib_proxy-0.1.0/src/moat_lib_proxy.egg-info/dependency_links.txt +1 -0
- moat_lib_proxy-0.1.0/src/moat_lib_proxy.egg-info/requires.txt +3 -0
- moat_lib_proxy-0.1.0/src/moat_lib_proxy.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
The code in this repository, and all MoaT submodules it refers to,
|
|
2
|
+
is part of the MoaT project.
|
|
3
|
+
|
|
4
|
+
Unless a submodule's LICENSE.txt states otherwise, all included files are
|
|
5
|
+
licensed under the LGPL V3, as published by the FSF at
|
|
6
|
+
https://www.gnu.org/licenses/lgpl-3.0.html .
|
|
7
|
+
|
|
8
|
+
In addition to the LGPL's terms, the author(s) respectfully ask all users of
|
|
9
|
+
this code to contribute any bug fixes or enhancements. Also, please link back to
|
|
10
|
+
https://M-o-a-T.org.
|
|
11
|
+
|
|
12
|
+
Thank you.
|
|
13
|
+
|
|
14
|
+
Copyright © 2021 ff.: the MoaT contributor(s), as per the git changelog(s).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/make -f
|
|
2
|
+
|
|
3
|
+
PACKAGE = moat-lib-proxy
|
|
4
|
+
MAKEINCL ?= $(shell python3 -mmoat src path)/make/py
|
|
5
|
+
|
|
6
|
+
ifneq ($(wildcard $(MAKEINCL)),)
|
|
7
|
+
include $(MAKEINCL)
|
|
8
|
+
# availabe via http://github.com/smurfix/sourcemgr
|
|
9
|
+
|
|
10
|
+
else
|
|
11
|
+
%:
|
|
12
|
+
@echo "Please fix 'python3 -mmoat src path'."
|
|
13
|
+
@exit 1
|
|
14
|
+
endif
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: moat-lib-proxy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Proxy helpers for serializing and deserializing objects
|
|
5
|
+
Maintainer-email: Matthias Urlichs <matthias@urlichs.de>
|
|
6
|
+
Project-URL: homepage, https://m-o-a-t.org
|
|
7
|
+
Project-URL: repository, https://github.com/M-o-a-T/moat
|
|
8
|
+
Keywords: MoaT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Framework :: AnyIO
|
|
11
|
+
Classifier: Framework :: Trio
|
|
12
|
+
Classifier: Framework :: AsyncIO
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Requires-Dist: anyio~=4.0
|
|
19
|
+
Requires-Dist: moat-util~=0.6
|
|
20
|
+
Requires-Dist: moat-lib-micro~=0.1.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Proxy helpers
|
|
24
|
+
|
|
25
|
+
% start main
|
|
26
|
+
% start synopsis
|
|
27
|
+
|
|
28
|
+
This module provides proxy helpers for serializing and deserializing objects
|
|
29
|
+
across process boundaries or network connections. It includes:
|
|
30
|
+
|
|
31
|
+
- Transparent proxy objects that can be serialized and reconstructed
|
|
32
|
+
- Object registration and name mapping for proxied objects
|
|
33
|
+
- Data-carrying proxies (DProxy) for including object state
|
|
34
|
+
- Integration with CBOR, msgpack, and other serialization formats
|
|
35
|
+
|
|
36
|
+
% end synopsis
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Basic proxy registration
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from moat.lib.proxy import name2obj, obj2name, Proxy
|
|
44
|
+
|
|
45
|
+
# Register a class for proxying
|
|
46
|
+
class MyService:
|
|
47
|
+
def do_something(self):
|
|
48
|
+
return "result"
|
|
49
|
+
|
|
50
|
+
# Register the class with a name
|
|
51
|
+
name2obj("myapp.MyService", MyService)
|
|
52
|
+
|
|
53
|
+
# Get the proxy name for an object
|
|
54
|
+
service = MyService()
|
|
55
|
+
proxy_name = obj2name(service) # Returns "myapp.MyService"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Using proxies
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from moat.lib.proxy import as_proxy, get_proxy
|
|
62
|
+
|
|
63
|
+
# Create a proxy reference to an object
|
|
64
|
+
obj = MyService()
|
|
65
|
+
proxy = as_proxy(obj) # Returns a Proxy object
|
|
66
|
+
|
|
67
|
+
# Later, retrieve the original object
|
|
68
|
+
original = get_proxy(proxy) # Returns the MyService instance
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Data-carrying proxies (DProxy)
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from moat.lib.proxy import DProxy
|
|
75
|
+
|
|
76
|
+
class MyData(DProxy):
|
|
77
|
+
"""A proxy that includes object state"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, value):
|
|
80
|
+
self.value = value
|
|
81
|
+
|
|
82
|
+
def __reduce__(self):
|
|
83
|
+
# Define how to serialize the object
|
|
84
|
+
return (self.__class__, (self.value,))
|
|
85
|
+
|
|
86
|
+
# The object can be serialized with its state
|
|
87
|
+
data = MyData(42)
|
|
88
|
+
# When serialized and deserialized, the value is preserved
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Working with serialization
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from moat.lib.proxy import wrap_obj, unwrap_obj
|
|
95
|
+
|
|
96
|
+
# Serialize an object for transmission
|
|
97
|
+
class MyObject:
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
name2obj("myapp.MyObject", MyObject)
|
|
101
|
+
obj = MyObject()
|
|
102
|
+
|
|
103
|
+
# Wrap for serialization
|
|
104
|
+
wrapped = wrap_obj(obj) # Creates a serializable representation
|
|
105
|
+
|
|
106
|
+
# Later, unwrap to reconstruct
|
|
107
|
+
reconstructed = unwrap_obj(wrapped) # Returns a MyObject instance
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Integration with Serialization Formats
|
|
111
|
+
|
|
112
|
+
This module integrates with MoaT's serialization libraries:
|
|
113
|
+
|
|
114
|
+
- **CBOR**: `moat.lib.codec.cbor`
|
|
115
|
+
- **Msgpack**: `moat.lib.codec.msgpack`
|
|
116
|
+
- **YAML**: Supports proxy references in configuration files
|
|
117
|
+
|
|
118
|
+
% end main
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Proxy helpers
|
|
2
|
+
|
|
3
|
+
% start main
|
|
4
|
+
% start synopsis
|
|
5
|
+
|
|
6
|
+
This module provides proxy helpers for serializing and deserializing objects
|
|
7
|
+
across process boundaries or network connections. It includes:
|
|
8
|
+
|
|
9
|
+
- Transparent proxy objects that can be serialized and reconstructed
|
|
10
|
+
- Object registration and name mapping for proxied objects
|
|
11
|
+
- Data-carrying proxies (DProxy) for including object state
|
|
12
|
+
- Integration with CBOR, msgpack, and other serialization formats
|
|
13
|
+
|
|
14
|
+
% end synopsis
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### Basic proxy registration
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from moat.lib.proxy import name2obj, obj2name, Proxy
|
|
22
|
+
|
|
23
|
+
# Register a class for proxying
|
|
24
|
+
class MyService:
|
|
25
|
+
def do_something(self):
|
|
26
|
+
return "result"
|
|
27
|
+
|
|
28
|
+
# Register the class with a name
|
|
29
|
+
name2obj("myapp.MyService", MyService)
|
|
30
|
+
|
|
31
|
+
# Get the proxy name for an object
|
|
32
|
+
service = MyService()
|
|
33
|
+
proxy_name = obj2name(service) # Returns "myapp.MyService"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Using proxies
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from moat.lib.proxy import as_proxy, get_proxy
|
|
40
|
+
|
|
41
|
+
# Create a proxy reference to an object
|
|
42
|
+
obj = MyService()
|
|
43
|
+
proxy = as_proxy(obj) # Returns a Proxy object
|
|
44
|
+
|
|
45
|
+
# Later, retrieve the original object
|
|
46
|
+
original = get_proxy(proxy) # Returns the MyService instance
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Data-carrying proxies (DProxy)
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from moat.lib.proxy import DProxy
|
|
53
|
+
|
|
54
|
+
class MyData(DProxy):
|
|
55
|
+
"""A proxy that includes object state"""
|
|
56
|
+
|
|
57
|
+
def __init__(self, value):
|
|
58
|
+
self.value = value
|
|
59
|
+
|
|
60
|
+
def __reduce__(self):
|
|
61
|
+
# Define how to serialize the object
|
|
62
|
+
return (self.__class__, (self.value,))
|
|
63
|
+
|
|
64
|
+
# The object can be serialized with its state
|
|
65
|
+
data = MyData(42)
|
|
66
|
+
# When serialized and deserialized, the value is preserved
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Working with serialization
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from moat.lib.proxy import wrap_obj, unwrap_obj
|
|
73
|
+
|
|
74
|
+
# Serialize an object for transmission
|
|
75
|
+
class MyObject:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
name2obj("myapp.MyObject", MyObject)
|
|
79
|
+
obj = MyObject()
|
|
80
|
+
|
|
81
|
+
# Wrap for serialization
|
|
82
|
+
wrapped = wrap_obj(obj) # Creates a serializable representation
|
|
83
|
+
|
|
84
|
+
# Later, unwrap to reconstruct
|
|
85
|
+
reconstructed = unwrap_obj(wrapped) # Returns a MyObject instance
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Integration with Serialization Formats
|
|
89
|
+
|
|
90
|
+
This module integrates with MoaT's serialization libraries:
|
|
91
|
+
|
|
92
|
+
- **CBOR**: `moat.lib.codec.cbor`
|
|
93
|
+
- **Msgpack**: `moat.lib.codec.msgpack`
|
|
94
|
+
- **YAML**: Supports proxy references in configuration files
|
|
95
|
+
|
|
96
|
+
% end main
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
moat-lib-proxy (0.1.0-5) unstable; urgency=medium
|
|
2
|
+
|
|
3
|
+
* New release for 25.7.0
|
|
4
|
+
|
|
5
|
+
-- Matthias Urlichs <matthias@urlichs.de> Wed, 31 Dec 2025 13:41:19 +0100
|
|
6
|
+
|
|
7
|
+
moat-lib-proxy (0.1.0-4) unstable; urgency=medium
|
|
8
|
+
|
|
9
|
+
* New release for 25.7.0
|
|
10
|
+
|
|
11
|
+
-- Matthias Urlichs <matthias@urlichs.de> Wed, 31 Dec 2025 09:42:20 +0100
|
|
12
|
+
|
|
13
|
+
moat-lib-proxy (0.1.0-3) unstable; urgency=medium
|
|
14
|
+
|
|
15
|
+
* New release for 25.7.0
|
|
16
|
+
|
|
17
|
+
-- Matthias Urlichs <matthias@urlichs.de> Wed, 31 Dec 2025 09:30:06 +0100
|
|
18
|
+
|
|
19
|
+
moat-lib-proxy (0.1.0-2) unstable; urgency=medium
|
|
20
|
+
|
|
21
|
+
* New release for 25.7.0
|
|
22
|
+
|
|
23
|
+
-- Matthias Urlichs <matthias@urlichs.de> Wed, 31 Dec 2025 08:57:53 +0100
|
|
24
|
+
|
|
25
|
+
moat-lib-proxy (0.1.0-1) unstable; urgency=medium
|
|
26
|
+
|
|
27
|
+
* Initial release
|
|
28
|
+
|
|
29
|
+
-- Matthias Urlichs <matthias@urlichs.de> Fri, 27 Dec 2024 00:00:00 +0100
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Source: moat-lib-proxy
|
|
2
|
+
Maintainer: "Matthias Urlichs" <matthias@urlichs.de>
|
|
3
|
+
Section: python
|
|
4
|
+
Priority: optional
|
|
5
|
+
Build-Depends: dh-python, python3-all, debhelper (>= 13),
|
|
6
|
+
python3-setuptools,
|
|
7
|
+
python3-wheel,
|
|
8
|
+
Standards-Version: 3.9.6
|
|
9
|
+
Homepage: https://m-o-a-t.org
|
|
10
|
+
X-DH-Compat: 13
|
|
11
|
+
|
|
12
|
+
Package: python3-moat-lib-proxy
|
|
13
|
+
Architecture: all
|
|
14
|
+
Depends: ${misc:Depends}, ${python3:Depends},
|
|
15
|
+
python3-anyio (>= 4.0),
|
|
16
|
+
python3-moat-util (>= 0.6),
|
|
17
|
+
Description: Proxy helpers for serializing and deserializing objects
|
|
18
|
+
This module provides proxy helpers for transparently serializing and
|
|
19
|
+
deserializing objects across process boundaries or network connections,
|
|
20
|
+
with integration for CBOR, msgpack, and other serialization formats.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "setuptools.build_meta"
|
|
3
|
+
requires = ["wheel","setuptools"]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
classifiers = [
|
|
7
|
+
"Development Status :: 4 - Beta",
|
|
8
|
+
"Framework :: AnyIO",
|
|
9
|
+
"Framework :: Trio",
|
|
10
|
+
"Framework :: AsyncIO",
|
|
11
|
+
"Programming Language :: Python :: 3",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
]
|
|
14
|
+
dependencies = [
|
|
15
|
+
"anyio ~= 4.0",
|
|
16
|
+
"moat-util ~= 0.6",
|
|
17
|
+
"moat-lib-micro ~= 0.1.0",
|
|
18
|
+
]
|
|
19
|
+
keywords = ["MoaT"]
|
|
20
|
+
requires-python = ">=3.8"
|
|
21
|
+
name = "moat-lib-proxy"
|
|
22
|
+
maintainers = [{email = "matthias@urlichs.de",name = "Matthias Urlichs"}]
|
|
23
|
+
description='Proxy helpers for serializing and deserializing objects'
|
|
24
|
+
readme = "README.md"
|
|
25
|
+
version = "0.1.0"
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
homepage = "https://m-o-a-t.org"
|
|
29
|
+
repository = "https://github.com/M-o-a-T/moat"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools]
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.package-data]
|
|
36
|
+
"*" = ["*.yaml"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Proxy helpers for MoaT applications.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from ._impl import DProxy as DProxy
|
|
8
|
+
from ._impl import NoProxyError as NoProxyError
|
|
9
|
+
from ._impl import Proxy as Proxy
|
|
10
|
+
from ._impl import _CProxy as _CProxy
|
|
11
|
+
from ._impl import as_proxy as as_proxy
|
|
12
|
+
from ._impl import drop_proxy as drop_proxy
|
|
13
|
+
from ._impl import get_proxy as get_proxy
|
|
14
|
+
from ._impl import name2obj as name2obj
|
|
15
|
+
from ._impl import obj2name as obj2name
|
|
16
|
+
from ._impl import unwrap_obj as unwrap_obj
|
|
17
|
+
from ._impl import wrap_obj as wrap_obj
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"DProxy",
|
|
21
|
+
"NoProxyError",
|
|
22
|
+
"Proxy",
|
|
23
|
+
"_CProxy",
|
|
24
|
+
"as_proxy",
|
|
25
|
+
"drop_proxy",
|
|
26
|
+
"get_proxy",
|
|
27
|
+
"name2obj",
|
|
28
|
+
"obj2name",
|
|
29
|
+
"unwrap_obj",
|
|
30
|
+
"wrap_obj",
|
|
31
|
+
]
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains proxy helpers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from inspect import isfunction
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"DProxy",
|
|
11
|
+
"NoProxyError",
|
|
12
|
+
"Proxy",
|
|
13
|
+
"_CProxy",
|
|
14
|
+
"as_proxy",
|
|
15
|
+
"drop_proxy",
|
|
16
|
+
"get_proxy",
|
|
17
|
+
"name2obj",
|
|
18
|
+
"obj2name",
|
|
19
|
+
"unwrap_obj",
|
|
20
|
+
"wrap_obj",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
from anyio import Path as AioPath
|
|
24
|
+
from pathlib import Path as FSPath
|
|
25
|
+
|
|
26
|
+
from moat.lib.proxy._proxy import DProxy as _DProxy
|
|
27
|
+
from moat.lib.proxy._proxy import (
|
|
28
|
+
NotGiven,
|
|
29
|
+
Proxy,
|
|
30
|
+
_CProxy,
|
|
31
|
+
as_proxy,
|
|
32
|
+
drop_proxy,
|
|
33
|
+
get_proxy,
|
|
34
|
+
name2obj,
|
|
35
|
+
obj2name,
|
|
36
|
+
)
|
|
37
|
+
from moat.util.pp import pop_kw, push_kw
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NoProxyError(ValueError):
|
|
41
|
+
"Error for nonexistent proxy values"
|
|
42
|
+
|
|
43
|
+
# pylint:disable=unnecessary-pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class DProxy(_DProxy):
|
|
47
|
+
"""
|
|
48
|
+
A proxy object with data. This is implemented as a type that's proxied,
|
|
49
|
+
thus the object can be reconstituted by the receiver (if it knows the
|
|
50
|
+
proxy class) or at least rebuilt when the original sender gets the
|
|
51
|
+
proxy structure back (if it doesn't). The object's state is included.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, name, a, k):
|
|
55
|
+
a = list(a) if a else []
|
|
56
|
+
super().__init__(name, a, k)
|
|
57
|
+
|
|
58
|
+
def append(self, val):
|
|
59
|
+
"Helper for deserializer"
|
|
60
|
+
self.a.append(val)
|
|
61
|
+
|
|
62
|
+
def __setitem__(self, key, val):
|
|
63
|
+
"Helper for deserializer"
|
|
64
|
+
self.k[key] = val
|
|
65
|
+
|
|
66
|
+
def __reduce__(self):
|
|
67
|
+
return (type(self), self.a, self.k)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
as_proxy("_", NotGiven)
|
|
71
|
+
as_proxy("_p", Proxy)
|
|
72
|
+
|
|
73
|
+
as_proxy("_fp", FSPath)
|
|
74
|
+
as_proxy("_fpa", AioPath)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _next(it, dfl=None):
|
|
78
|
+
try:
|
|
79
|
+
return next(it)
|
|
80
|
+
except StopIteration:
|
|
81
|
+
return dfl
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def wrap_obj(obj, name=None):
|
|
85
|
+
"Serialize an object"
|
|
86
|
+
if name is None:
|
|
87
|
+
name = obj2name(type(obj))
|
|
88
|
+
try:
|
|
89
|
+
p = obj.__reduce__()
|
|
90
|
+
if not isinstance(p, (list, tuple)):
|
|
91
|
+
res = (name, (), p)
|
|
92
|
+
elif hasattr(p[0], "__name__"): # grah
|
|
93
|
+
if p[0].__name__ == "_reconstructor":
|
|
94
|
+
_, _o, ak = p
|
|
95
|
+
if len(ak) == 1:
|
|
96
|
+
k = ak
|
|
97
|
+
a = []
|
|
98
|
+
else:
|
|
99
|
+
a, k = ak
|
|
100
|
+
res = [name]
|
|
101
|
+
res.extend(a)
|
|
102
|
+
push_kw(res, k)
|
|
103
|
+
elif p[0].__name__ == "__newobj__":
|
|
104
|
+
raise NotImplementedError(p)
|
|
105
|
+
res = (p[1][0], p[1][1:]) + tuple(p[2:])
|
|
106
|
+
else:
|
|
107
|
+
res = (name,) + p[1]
|
|
108
|
+
if (len(p) == 3 and p[2]) or isinstance(p[-1], dict):
|
|
109
|
+
res += (p[2],)
|
|
110
|
+
elif len(p) > 3:
|
|
111
|
+
raise NotImplementedError(p)
|
|
112
|
+
|
|
113
|
+
elif p[0] is not type(obj):
|
|
114
|
+
raise ValueError(f"Reducer for {obj!r}")
|
|
115
|
+
else:
|
|
116
|
+
raise NotImplementedError(p)
|
|
117
|
+
res = (name,) + p[1]
|
|
118
|
+
return res
|
|
119
|
+
|
|
120
|
+
except (AttributeError, ValueError):
|
|
121
|
+
p = obj.__getstate__()
|
|
122
|
+
if isinstance(p, dict):
|
|
123
|
+
p = (p,)
|
|
124
|
+
return (name,) + p
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def unwrap_obj(s):
|
|
128
|
+
"Deserialize an object"
|
|
129
|
+
pk, *a = s
|
|
130
|
+
if not isinstance(pk, type):
|
|
131
|
+
# otherwise it was tagged and de-proxied already
|
|
132
|
+
if isinstance(pk, Proxy):
|
|
133
|
+
pk = pk.name
|
|
134
|
+
try:
|
|
135
|
+
pk = _CProxy[pk]
|
|
136
|
+
except KeyError:
|
|
137
|
+
kw = pop_kw(a)
|
|
138
|
+
return DProxy(pk, a, kw)
|
|
139
|
+
kw = pop_kw(a)
|
|
140
|
+
|
|
141
|
+
if isfunction(pk):
|
|
142
|
+
return pk(*a, **kw)
|
|
143
|
+
|
|
144
|
+
if (pkr := getattr(pk, "_moat__restore", None)) is not None:
|
|
145
|
+
pk = pkr(a, kw)
|
|
146
|
+
else:
|
|
147
|
+
try:
|
|
148
|
+
pk = pk(*a, **kw)
|
|
149
|
+
except (TypeError, ValueError):
|
|
150
|
+
if not issubclass(pk, Exception):
|
|
151
|
+
raise
|
|
152
|
+
pk = pk(*a)
|
|
153
|
+
for k, v in kw.items():
|
|
154
|
+
setattr(pk, k, v)
|
|
155
|
+
return pk
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A hacked-up copy of some parts of `moat.util`.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Callable
|
|
11
|
+
from typing import Any, TypeVar, overload
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"DProxy",
|
|
15
|
+
"NoProxyError",
|
|
16
|
+
"Proxy",
|
|
17
|
+
"as_proxy",
|
|
18
|
+
"drop_proxy",
|
|
19
|
+
"get_proxy",
|
|
20
|
+
"name2obj",
|
|
21
|
+
"obj2name",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
NotGiven = ... # from moat.util import NotGiven
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_pkey = 1
|
|
28
|
+
_CProxy = {} # name > object
|
|
29
|
+
_RProxy = {} # object > name
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def name2obj(name, obj=NotGiven):
|
|
33
|
+
"""
|
|
34
|
+
Given a proxy name, return the referred object.
|
|
35
|
+
|
|
36
|
+
If @obj is given, associate.
|
|
37
|
+
"""
|
|
38
|
+
if obj is NotGiven and _CProxy:
|
|
39
|
+
return _CProxy[name]
|
|
40
|
+
_CProxy[name] = obj
|
|
41
|
+
_RProxy[id(obj)] = name
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def obj2name(obj):
|
|
46
|
+
"""
|
|
47
|
+
Given a proxied object, return the name referring to it.
|
|
48
|
+
"""
|
|
49
|
+
return _RProxy[id(obj)]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def get_proxy(obj):
|
|
53
|
+
"""
|
|
54
|
+
Given a proxied object, return the name referring to it.
|
|
55
|
+
|
|
56
|
+
If unknown, create a new temporary name.
|
|
57
|
+
"""
|
|
58
|
+
try:
|
|
59
|
+
return _RProxy[id(obj)]
|
|
60
|
+
except KeyError:
|
|
61
|
+
global _pkey
|
|
62
|
+
k = "p_" + str(_pkey)
|
|
63
|
+
_pkey += 1
|
|
64
|
+
_CProxy[k] = obj
|
|
65
|
+
_RProxy[id(obj)] = k
|
|
66
|
+
return k
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# def _getstate(self):
|
|
70
|
+
# return (type(self), (), self.__dict__)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if TYPE_CHECKING:
|
|
74
|
+
T = TypeVar("T")
|
|
75
|
+
|
|
76
|
+
@overload
|
|
77
|
+
def as_proxy(name: str) -> Callable[[T], T]: ...
|
|
78
|
+
|
|
79
|
+
@overload
|
|
80
|
+
def as_proxy(name: str, obj: Any, replace: bool = False) -> None: ...
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def as_proxy(name: str, obj: Any = NotImplemented, replace: bool = False):
|
|
84
|
+
"""
|
|
85
|
+
Export an object as a named proxy.
|
|
86
|
+
Usage:
|
|
87
|
+
|
|
88
|
+
@as_proxy("foo")
|
|
89
|
+
class Foo():
|
|
90
|
+
def __
|
|
91
|
+
"""
|
|
92
|
+
# This uses NotImplemented instead of None or Ellipsis/NotGiven because
|
|
93
|
+
# those two are be legitimately proxied.
|
|
94
|
+
|
|
95
|
+
def _proxy(obj):
|
|
96
|
+
"Export @obj as a proxy."
|
|
97
|
+
if not replace and name in _CProxy and _CProxy[name] is not obj:
|
|
98
|
+
raise ValueError("Proxy: " + repr(name) + " already exists")
|
|
99
|
+
_CProxy[name] = obj
|
|
100
|
+
_RProxy[id(obj)] = name
|
|
101
|
+
# if isinstance(obj,type) and not hasattr(obj,"__getstate__"):
|
|
102
|
+
# obj.__getstate__ = _getstate
|
|
103
|
+
return obj
|
|
104
|
+
|
|
105
|
+
if obj is NotImplemented:
|
|
106
|
+
return _proxy
|
|
107
|
+
else:
|
|
108
|
+
_proxy(obj)
|
|
109
|
+
return obj
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def drop_proxy(p):
|
|
113
|
+
"""
|
|
114
|
+
After sending a proxy we keep it in memory in case the remote returns
|
|
115
|
+
it, or an expression with it.
|
|
116
|
+
|
|
117
|
+
If that won't happen, the remote needs to tell us to clean it up.
|
|
118
|
+
"""
|
|
119
|
+
if not isinstance(p, str):
|
|
120
|
+
p = _RProxy[id(p)]
|
|
121
|
+
if p == "" or p[0] == "_":
|
|
122
|
+
raise ValueError("Can't delete a system proxy")
|
|
123
|
+
r = _CProxy.pop(p)
|
|
124
|
+
del _RProxy[id(r)]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class NoProxyError(ValueError):
|
|
128
|
+
"Error for nonexistent proxy values"
|
|
129
|
+
|
|
130
|
+
# pylint:disable=unnecessary-pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class Proxy:
|
|
134
|
+
"""
|
|
135
|
+
A proxy object, i.e. a placeholder for things that cannot pass
|
|
136
|
+
through a codec. No object data are included.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
def __init__(self, name):
|
|
140
|
+
self.name = name
|
|
141
|
+
|
|
142
|
+
def __repr__(self):
|
|
143
|
+
return f"{self.__class__.__name__}({self.name!r})"
|
|
144
|
+
|
|
145
|
+
def ref(self):
|
|
146
|
+
"""Dereferences the proxy"""
|
|
147
|
+
return name2obj(self.name)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class DProxy(Proxy):
|
|
151
|
+
"""
|
|
152
|
+
A proxy object with data. This is implemented as a type that's proxied,
|
|
153
|
+
thus the object can be reconstituted by the receiver (if it knows the
|
|
154
|
+
proxy class) or at least rebuilt when the original sender gets the
|
|
155
|
+
proxy structure back (if it doesn't). The object's state is included.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
def __init__(self, name, a, k):
|
|
159
|
+
super().__init__(name)
|
|
160
|
+
self.a = a
|
|
161
|
+
self.k = k
|
|
162
|
+
|
|
163
|
+
def __getitem__(self, i):
|
|
164
|
+
if i in self.k:
|
|
165
|
+
return self.k[i]
|
|
166
|
+
else:
|
|
167
|
+
try:
|
|
168
|
+
return self.a[i]
|
|
169
|
+
except TypeError:
|
|
170
|
+
from moat.lib.micro import log # noqa: PLC0415
|
|
171
|
+
|
|
172
|
+
log("*ERR %r", self.k)
|
|
173
|
+
raise KeyError(i) from None
|
|
174
|
+
|
|
175
|
+
def __eq__(self, other):
|
|
176
|
+
if not isinstance(other, DProxy):
|
|
177
|
+
return NotImplemented
|
|
178
|
+
|
|
179
|
+
# Split into several lines so we can selectively set breakpoints
|
|
180
|
+
# when debugging
|
|
181
|
+
if self.name != other.name:
|
|
182
|
+
return False
|
|
183
|
+
if self.a != other.a or self.k != other.k:
|
|
184
|
+
return False
|
|
185
|
+
return True
|
|
186
|
+
|
|
187
|
+
def __repr__(self):
|
|
188
|
+
return (
|
|
189
|
+
f"{self.__class__.__name__}({self.name!r},"
|
|
190
|
+
+ ",".join(repr(x) for x in (self.a, self.k))
|
|
191
|
+
+ ")"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
def ref(self):
|
|
195
|
+
"""Dereferences the proxy"""
|
|
196
|
+
return name2obj(self.name)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: moat-lib-proxy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Proxy helpers for serializing and deserializing objects
|
|
5
|
+
Maintainer-email: Matthias Urlichs <matthias@urlichs.de>
|
|
6
|
+
Project-URL: homepage, https://m-o-a-t.org
|
|
7
|
+
Project-URL: repository, https://github.com/M-o-a-T/moat
|
|
8
|
+
Keywords: MoaT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Framework :: AnyIO
|
|
11
|
+
Classifier: Framework :: Trio
|
|
12
|
+
Classifier: Framework :: AsyncIO
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Requires-Dist: anyio~=4.0
|
|
19
|
+
Requires-Dist: moat-util~=0.6
|
|
20
|
+
Requires-Dist: moat-lib-micro~=0.1.0
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Proxy helpers
|
|
24
|
+
|
|
25
|
+
% start main
|
|
26
|
+
% start synopsis
|
|
27
|
+
|
|
28
|
+
This module provides proxy helpers for serializing and deserializing objects
|
|
29
|
+
across process boundaries or network connections. It includes:
|
|
30
|
+
|
|
31
|
+
- Transparent proxy objects that can be serialized and reconstructed
|
|
32
|
+
- Object registration and name mapping for proxied objects
|
|
33
|
+
- Data-carrying proxies (DProxy) for including object state
|
|
34
|
+
- Integration with CBOR, msgpack, and other serialization formats
|
|
35
|
+
|
|
36
|
+
% end synopsis
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Basic proxy registration
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from moat.lib.proxy import name2obj, obj2name, Proxy
|
|
44
|
+
|
|
45
|
+
# Register a class for proxying
|
|
46
|
+
class MyService:
|
|
47
|
+
def do_something(self):
|
|
48
|
+
return "result"
|
|
49
|
+
|
|
50
|
+
# Register the class with a name
|
|
51
|
+
name2obj("myapp.MyService", MyService)
|
|
52
|
+
|
|
53
|
+
# Get the proxy name for an object
|
|
54
|
+
service = MyService()
|
|
55
|
+
proxy_name = obj2name(service) # Returns "myapp.MyService"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Using proxies
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from moat.lib.proxy import as_proxy, get_proxy
|
|
62
|
+
|
|
63
|
+
# Create a proxy reference to an object
|
|
64
|
+
obj = MyService()
|
|
65
|
+
proxy = as_proxy(obj) # Returns a Proxy object
|
|
66
|
+
|
|
67
|
+
# Later, retrieve the original object
|
|
68
|
+
original = get_proxy(proxy) # Returns the MyService instance
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Data-carrying proxies (DProxy)
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from moat.lib.proxy import DProxy
|
|
75
|
+
|
|
76
|
+
class MyData(DProxy):
|
|
77
|
+
"""A proxy that includes object state"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, value):
|
|
80
|
+
self.value = value
|
|
81
|
+
|
|
82
|
+
def __reduce__(self):
|
|
83
|
+
# Define how to serialize the object
|
|
84
|
+
return (self.__class__, (self.value,))
|
|
85
|
+
|
|
86
|
+
# The object can be serialized with its state
|
|
87
|
+
data = MyData(42)
|
|
88
|
+
# When serialized and deserialized, the value is preserved
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Working with serialization
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from moat.lib.proxy import wrap_obj, unwrap_obj
|
|
95
|
+
|
|
96
|
+
# Serialize an object for transmission
|
|
97
|
+
class MyObject:
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
name2obj("myapp.MyObject", MyObject)
|
|
101
|
+
obj = MyObject()
|
|
102
|
+
|
|
103
|
+
# Wrap for serialization
|
|
104
|
+
wrapped = wrap_obj(obj) # Creates a serializable representation
|
|
105
|
+
|
|
106
|
+
# Later, unwrap to reconstruct
|
|
107
|
+
reconstructed = unwrap_obj(wrapped) # Returns a MyObject instance
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Integration with Serialization Formats
|
|
111
|
+
|
|
112
|
+
This module integrates with MoaT's serialization libraries:
|
|
113
|
+
|
|
114
|
+
- **CBOR**: `moat.lib.codec.cbor`
|
|
115
|
+
- **Msgpack**: `moat.lib.codec.msgpack`
|
|
116
|
+
- **YAML**: Supports proxy references in configuration files
|
|
117
|
+
|
|
118
|
+
% end main
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
Makefile
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
debian/.gitignore
|
|
6
|
+
debian/changelog
|
|
7
|
+
debian/control
|
|
8
|
+
debian/rules
|
|
9
|
+
src/moat/lib/proxy/__init__.py
|
|
10
|
+
src/moat/lib/proxy/_impl.py
|
|
11
|
+
src/moat/lib/proxy/_proxy.py
|
|
12
|
+
src/moat_lib_proxy.egg-info/PKG-INFO
|
|
13
|
+
src/moat_lib_proxy.egg-info/SOURCES.txt
|
|
14
|
+
src/moat_lib_proxy.egg-info/dependency_links.txt
|
|
15
|
+
src/moat_lib_proxy.egg-info/requires.txt
|
|
16
|
+
src/moat_lib_proxy.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
moat
|