pyrpc-django-adapter 0.7.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.
@@ -0,0 +1,161 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ !docs/lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Used for packaging Python scripts into standalone executables
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .stats
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ pytestdebug.log
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # Project-specific python versions
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if Pipfile.lock (and requirements.txt) are not
93
+ # preferred, then add them into the ignore list.
94
+ # Pipfile.lock
95
+
96
+ # poetry
97
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
98
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
99
+ # poetry.lock
100
+
101
+ # pdm
102
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
103
+ # pdm.lock
104
+ # .pdm-python
105
+
106
+ # PEP 582; used by e.g. github.com/fannheyward/coc-pyright
107
+ __pypackages__/
108
+
109
+ # Celery stuff
110
+ celerybeat-schedule
111
+ celerybeat.pid
112
+
113
+ # SageMath parsed files
114
+ *.sage.py
115
+
116
+ # Environments
117
+ .env
118
+ .venv
119
+ env/
120
+ venv/
121
+ ENV/
122
+ env.bak/
123
+ venv.bak/
124
+
125
+ # Spyder project settings
126
+ .spyderproject
127
+ .spyderformpoint
128
+
129
+ # Rope project settings
130
+ .ropeproject
131
+
132
+ # mkdocs documentation
133
+ /site
134
+
135
+ # mypy
136
+ .mypy_cache/
137
+ .dmypy.json
138
+ dmypy.json
139
+
140
+ # Pyre type checker
141
+ .pyre/
142
+
143
+ # pytype static type analyzer
144
+ .pytype/
145
+
146
+ # Cython debug symbols
147
+ cython_debug/
148
+
149
+ # OS X
150
+ .DS_Store
151
+
152
+ # Node modules
153
+ node_modules
154
+ dist
155
+
156
+
157
+ # System design docs (local developer documentation)
158
+ system-design/
159
+
160
+ # Scripts
161
+ scripts/seed_downloads.py
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyrpc-django-adapter
3
+ Version: 0.7.2
4
+ Summary: Django adapter for pyRPC
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: django>=4.2.0
7
+ Requires-Dist: pyrpc-core
@@ -0,0 +1,16 @@
1
+ [project]
2
+ name = "pyrpc-django-adapter"
3
+ version = "0.7.2"
4
+ description = "Django adapter for pyRPC"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "pyrpc-core",
8
+ "django>=4.2.0",
9
+ ]
10
+
11
+ [build-system]
12
+ requires = ["hatchling"]
13
+ build-backend = "hatchling.build"
14
+
15
+ [tool.hatch.build.targets.wheel]
16
+ packages = ["src/pyrpc_django"]
@@ -0,0 +1,38 @@
1
+ from pyrpc_core import handle_request, Router, rpc, model, default_router
2
+ from typing import Any, Optional
3
+
4
+
5
+ def mount_django(urlpatterns: list, router: Optional[Router] = None) -> None:
6
+ from django.http import HttpRequest, JsonResponse
7
+ from django.urls import path
8
+ from django.views.decorators.csrf import csrf_exempt
9
+ import json
10
+
11
+ resolved = router or default_router
12
+
13
+ @csrf_exempt
14
+ async def rpc_endpoint(request: HttpRequest) -> JsonResponse:
15
+ if request.method != "POST":
16
+ return JsonResponse({"error": "Method not allowed"}, status=405)
17
+ try:
18
+ payload = json.loads(request.body)
19
+ except json.JSONDecodeError:
20
+ return JsonResponse({"error": "Invalid JSON"}, status=400)
21
+ response_dict = await handle_request(payload, router=resolved)
22
+ return JsonResponse(response_dict)
23
+
24
+ @csrf_exempt
25
+ async def introspection_endpoint(request: HttpRequest) -> JsonResponse:
26
+ if request.method != "GET":
27
+ return JsonResponse({"error": "Method not allowed"}, status=405)
28
+ from pyrpc_core import get_registry_schema
29
+ schemas = get_registry_schema(resolved)
30
+ return JsonResponse({
31
+ name: schema.model_dump() if hasattr(schema, "model_dump") else schema
32
+ for name, schema in schemas.items()
33
+ })
34
+
35
+ urlpatterns.extend([
36
+ path("rpc", rpc_endpoint, name="pyrpc-rpc"),
37
+ path("rpc", introspection_endpoint, name="pyrpc-introspection"),
38
+ ])
@@ -0,0 +1,12 @@
1
+ import django
2
+ from django.conf import settings
3
+
4
+ settings.configure(
5
+ DEBUG=True,
6
+ SECRET_KEY="test-secret-key-for-pyrpc",
7
+ ROOT_URLCONF=__name__,
8
+ ALLOWED_HOSTS=["*"],
9
+ INSTALLED_APPS=["django.contrib.contenttypes", "django.contrib.auth"],
10
+ DATABASES={"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": ":memory:"}},
11
+ )
12
+ django.setup()
@@ -0,0 +1,82 @@
1
+ import json
2
+ import anyio
3
+ import pytest
4
+ from pyrpc_core import rpc, default_router
5
+
6
+
7
+ @pytest.fixture(autouse=True)
8
+ def clear_registry():
9
+ default_router._procedures.clear()
10
+
11
+
12
+ def test_django_mount_success():
13
+ from pyrpc_django import mount_django
14
+ from django.test import RequestFactory
15
+
16
+ @rpc
17
+ def greet(name: str) -> str:
18
+ return f"Hello {name}"
19
+
20
+ urlpatterns = []
21
+ mount_django(urlpatterns)
22
+
23
+ factory = RequestFactory()
24
+ payload = {"id": "d-1", "method": "greet", "params": {"name": "Django"}}
25
+ request = factory.post("/rpc", json.dumps(payload), content_type="application/json")
26
+
27
+ async def run():
28
+ response = await urlpatterns[0].callback(request)
29
+ assert response.status_code == 200
30
+ data = json.loads(response.content)
31
+ assert data["id"] == "d-1"
32
+ assert data["result"] == "Hello Django"
33
+ assert data["error"] is None
34
+
35
+ anyio.run(run)
36
+
37
+
38
+ def test_django_async_procedure():
39
+ from pyrpc_django import mount_django
40
+ from django.test import RequestFactory
41
+
42
+ @rpc
43
+ async def async_greet(name: str) -> str:
44
+ return f"Async Hello {name}"
45
+
46
+ urlpatterns = []
47
+ mount_django(urlpatterns)
48
+
49
+ factory = RequestFactory()
50
+ payload = {"id": "d-2", "method": "async_greet", "params": {"name": "World"}}
51
+ request = factory.post("/rpc", json.dumps(payload), content_type="application/json")
52
+
53
+ async def run():
54
+ response = await urlpatterns[0].callback(request)
55
+ assert response.status_code == 200
56
+ data = json.loads(response.content)
57
+ assert data["result"] == "Async Hello World"
58
+
59
+ anyio.run(run)
60
+
61
+
62
+ def test_django_introspection():
63
+ from pyrpc_django import mount_django
64
+ from django.test import RequestFactory
65
+
66
+ @rpc
67
+ def add(a: int, b: int) -> int:
68
+ return a + b
69
+
70
+ urlpatterns = []
71
+ mount_django(urlpatterns)
72
+
73
+ factory = RequestFactory()
74
+ request = factory.get("/rpc")
75
+
76
+ async def run():
77
+ response = await urlpatterns[1].callback(request)
78
+ assert response.status_code == 200
79
+ data = json.loads(response.content)
80
+ assert "add" in data
81
+
82
+ anyio.run(run)