django-jsonrpc-framework 0.2.0__tar.gz → 0.2.1__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.
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/PKG-INFO +16 -12
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/README.md +10 -10
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/auth/bearer.py +1 -2
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/openrpc/collectors/_method_collector.py +0 -11
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/core/error.py +15 -1
- django_jsonrpc_framework-0.2.1/jsonrpc_framework/integration/prometheus/__init__.py +3 -0
- django_jsonrpc_framework-0.2.1/jsonrpc_framework/integration/prometheus/_prometheus.py +229 -0
- django_jsonrpc_framework-0.2.1/jsonrpc_framework/integration/sentry.py +125 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/logic/dispatcher.py +0 -15
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/components/_components.py +0 -9
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/_conftest/components_conftest.py +0 -10
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/_conftest/info_conftest.py +0 -7
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/_conftest/method_conftest.py +0 -28
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/test_builder.py +0 -2
- django_jsonrpc_framework-0.2.1/jsonrpc_framework/py.typed +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/pyproject.toml +4 -4
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/.gitignore +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/_base.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/_route.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/auth/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/auth/_base.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/decor.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/openrpc/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/openrpc/_openrpc.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/openrpc/collectors/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/controller/openrpc/collectors/_main_collector.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/core/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/core/models.py +0 -0
- {django_jsonrpc_framework-0.2.0/jsonrpc_framework/openrpc → django_jsonrpc_framework-0.2.1/jsonrpc_framework/integration}/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/logic/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/logic/responser.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/logic/validator.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/management/commands/generate_openrpc.py +0 -0
- {django_jsonrpc_framework-0.2.0/jsonrpc_framework/openrpc/builder → django_jsonrpc_framework-0.2.1/jsonrpc_framework/openrpc}/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0/jsonrpc_framework/openrpc/document → django_jsonrpc_framework-0.2.1/jsonrpc_framework/openrpc/builder}/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/builder/builder.py +0 -0
- {django_jsonrpc_framework-0.2.0/jsonrpc_framework/openrpc/tests → django_jsonrpc_framework-0.2.1/jsonrpc_framework/openrpc/document}/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/_base.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/_openrpc_document.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_descriptor.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_error.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_example.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_link.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_link_server.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_pairing_object.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_reference.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_schema.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_tag.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/common/_utils.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/components/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/external_docs/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/external_docs/_external_docs.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/info/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/info/_info.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/method/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/method/_method.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/server/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/document/server/_server.py +0 -0
- /django_jsonrpc_framework-0.2.0/jsonrpc_framework/openrpc/tests/_conftest/builder_conftest.py → /django_jsonrpc_framework-0.2.1/jsonrpc_framework/openrpc/tests/__init__.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/_conftest/__init__.py +0 -0
- /django_jsonrpc_framework-0.2.0/jsonrpc_framework/py.typed → /django_jsonrpc_framework-0.2.1/jsonrpc_framework/openrpc/tests/_conftest/builder_conftest.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/_conftest/external_doc_conftest.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/_conftest/server_conftest.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/conftest.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/test_components.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/test_external_doc.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/test_openrcp_info.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/test_openrcp_method.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/openrpc/tests/test_server.py +0 -0
- {django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/templates/openrpc_docs.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: django-jsonrpc-framework
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Django jsonrpc implementation
|
|
5
5
|
Classifier: Framework :: Django
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -9,11 +9,15 @@ Requires-Dist: django>=6.0.5
|
|
|
9
9
|
Requires-Dist: pydantic>=2.13.4
|
|
10
10
|
Provides-Extra: jwt
|
|
11
11
|
Requires-Dist: pyjwt>=2.13.0; extra == 'jwt'
|
|
12
|
+
Provides-Extra: prometheus
|
|
13
|
+
Requires-Dist: prometheus-client>=0.21; extra == 'prometheus'
|
|
14
|
+
Provides-Extra: sentry
|
|
15
|
+
Requires-Dist: sentry-sdk>=2.0; extra == 'sentry'
|
|
12
16
|
Description-Content-Type: text/markdown
|
|
13
17
|
|
|
14
18
|
# Django jsonrpc implementation
|
|
15
19
|
|
|
16
|
-
##
|
|
20
|
+
## Install
|
|
17
21
|
|
|
18
22
|
```
|
|
19
23
|
pip install django-jsonrpc-framework
|
|
@@ -21,18 +25,18 @@ pip install django-jsonrpc-framework
|
|
|
21
25
|
|
|
22
26
|
## Advantages
|
|
23
27
|
|
|
24
|
-
- Complete support
|
|
25
|
-
- Auto
|
|
26
|
-
- Auto
|
|
28
|
+
- Complete support for JSON-RPC 2.0 (Request, Notification, Batch)
|
|
29
|
+
- Auto-generation of `openrpc.json` (OpenRPC 1.3.2)
|
|
30
|
+
- Auto-generation of OpenRPC documentation (like Swagger)
|
|
27
31
|
- Async support
|
|
28
32
|
|
|
29
33
|
## Create methods
|
|
30
34
|
|
|
31
|
-
We provide several
|
|
35
|
+
We provide several ways to create methods.
|
|
32
36
|
|
|
33
37
|
- Using `method_` prefix
|
|
34
38
|
- Using `jsonrpc_method` decorator
|
|
35
|
-
- Rename existing
|
|
39
|
+
- Rename an existing function to a new name
|
|
36
40
|
|
|
37
41
|
``` python
|
|
38
42
|
from jsonrpc_framework import BaseController
|
|
@@ -49,7 +53,7 @@ class EchoController(BaseController):
|
|
|
49
53
|
|
|
50
54
|
@jsonrpc_method("echo_see_you")
|
|
51
55
|
def wrong_name(self, name) -> str:
|
|
52
|
-
return "See you
|
|
56
|
+
return "See you from echo_see_you method"
|
|
53
57
|
```
|
|
54
58
|
|
|
55
59
|
## Adding several controllers to one controller
|
|
@@ -76,7 +80,7 @@ route = RouteController(
|
|
|
76
80
|
)
|
|
77
81
|
```
|
|
78
82
|
|
|
79
|
-
##
|
|
83
|
+
## Generating openrpc.json and OpenRPC documentation
|
|
80
84
|
|
|
81
85
|
``` python
|
|
82
86
|
from jsonrpc_framework.controller.openrpc.collectors import OpenRpcCollector
|
|
@@ -94,10 +98,10 @@ urlpatterns = [
|
|
|
94
98
|
]
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
###
|
|
101
|
+
### OpenRPC.json example
|
|
98
102
|
|
|
99
103
|

|
|
100
104
|
|
|
101
|
-
##
|
|
105
|
+
## OpenRPC doc example
|
|
102
106
|
|
|
103
107
|

|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Django jsonrpc implementation
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Install
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
pip install django-jsonrpc-framework
|
|
@@ -8,18 +8,18 @@ pip install django-jsonrpc-framework
|
|
|
8
8
|
|
|
9
9
|
## Advantages
|
|
10
10
|
|
|
11
|
-
- Complete support
|
|
12
|
-
- Auto
|
|
13
|
-
- Auto
|
|
11
|
+
- Complete support for JSON-RPC 2.0 (Request, Notification, Batch)
|
|
12
|
+
- Auto-generation of `openrpc.json` (OpenRPC 1.3.2)
|
|
13
|
+
- Auto-generation of OpenRPC documentation (like Swagger)
|
|
14
14
|
- Async support
|
|
15
15
|
|
|
16
16
|
## Create methods
|
|
17
17
|
|
|
18
|
-
We provide several
|
|
18
|
+
We provide several ways to create methods.
|
|
19
19
|
|
|
20
20
|
- Using `method_` prefix
|
|
21
21
|
- Using `jsonrpc_method` decorator
|
|
22
|
-
- Rename existing
|
|
22
|
+
- Rename an existing function to a new name
|
|
23
23
|
|
|
24
24
|
``` python
|
|
25
25
|
from jsonrpc_framework import BaseController
|
|
@@ -36,7 +36,7 @@ class EchoController(BaseController):
|
|
|
36
36
|
|
|
37
37
|
@jsonrpc_method("echo_see_you")
|
|
38
38
|
def wrong_name(self, name) -> str:
|
|
39
|
-
return "See you
|
|
39
|
+
return "See you from echo_see_you method"
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
## Adding several controllers to one controller
|
|
@@ -63,7 +63,7 @@ route = RouteController(
|
|
|
63
63
|
)
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
##
|
|
66
|
+
## Generating openrpc.json and OpenRPC documentation
|
|
67
67
|
|
|
68
68
|
``` python
|
|
69
69
|
from jsonrpc_framework.controller.openrpc.collectors import OpenRpcCollector
|
|
@@ -81,10 +81,10 @@ urlpatterns = [
|
|
|
81
81
|
]
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
###
|
|
84
|
+
### OpenRPC.json example
|
|
85
85
|
|
|
86
86
|

|
|
87
87
|
|
|
88
|
-
##
|
|
88
|
+
## OpenRPC doc example
|
|
89
89
|
|
|
90
90
|

|
|
@@ -19,17 +19,6 @@ from jsonrpc_framework.openrpc.document.common import (
|
|
|
19
19
|
)
|
|
20
20
|
|
|
21
21
|
from jsonrpc_framework.core.error import RpcError
|
|
22
|
-
from jsonrpc_framework.openrpc.document.common import (
|
|
23
|
-
OpenRcpContentDescriptorObject,
|
|
24
|
-
OpenRcpTypeSchema,
|
|
25
|
-
OpenRpcDataSchema,
|
|
26
|
-
OpenRpcErrorObject,
|
|
27
|
-
OpenRpcRefSchema,
|
|
28
|
-
OpenRpcTag,
|
|
29
|
-
validate_type_name,
|
|
30
|
-
)
|
|
31
|
-
from jsonrpc_framework.openrpc.document.components import OpenRpcComponents
|
|
32
|
-
from jsonrpc_framework.openrpc.document.method._method import OpenRpcMethod
|
|
33
22
|
|
|
34
23
|
|
|
35
24
|
class ExampleCollector: ...
|
{django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/core/error.py
RENAMED
|
@@ -3,6 +3,20 @@ from typing import Any
|
|
|
3
3
|
from pydantic import BaseModel
|
|
4
4
|
|
|
5
5
|
|
|
6
|
+
__all__ = [
|
|
7
|
+
"RpcError",
|
|
8
|
+
"ParseError",
|
|
9
|
+
"InvalidRequestError",
|
|
10
|
+
"MethodNotFoundError",
|
|
11
|
+
"InvalidParamsError",
|
|
12
|
+
"InternalError",
|
|
13
|
+
"ParseExcError",
|
|
14
|
+
"InvalidRequestExcError",
|
|
15
|
+
"UnauthorizedError",
|
|
16
|
+
"ForbiddenError",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
6
20
|
class RpcError(BaseModel):
|
|
7
21
|
code: int
|
|
8
22
|
message: str
|
|
@@ -46,7 +60,7 @@ class InvalidRequestExcError(Exception): ...
|
|
|
46
60
|
|
|
47
61
|
class UnauthorizedError(RpcError):
|
|
48
62
|
code: int = -32001
|
|
49
|
-
message: str = "
|
|
63
|
+
message: str = "Unauthenticated"
|
|
50
64
|
|
|
51
65
|
|
|
52
66
|
class ForbiddenError(RpcError):
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
from jsonrpc_framework.logic.dispatcher import RpcDispatcher
|
|
7
|
+
from jsonrpc_framework.core.error import RpcError
|
|
8
|
+
from jsonrpc_framework.core.models import ErrorResponse
|
|
9
|
+
from django.views import View
|
|
10
|
+
from django.http import HttpResponse
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from prometheus_client import (
|
|
14
|
+
CONTENT_TYPE_LATEST,
|
|
15
|
+
REGISTRY,
|
|
16
|
+
CollectorRegistry,
|
|
17
|
+
Counter,
|
|
18
|
+
Histogram,
|
|
19
|
+
generate_latest,
|
|
20
|
+
)
|
|
21
|
+
except ImportError:
|
|
22
|
+
raise ImportError(
|
|
23
|
+
"prometheus-client is not installed, please install it with "
|
|
24
|
+
"`pip install django-jsonrpc-framework[prometheus]`"
|
|
25
|
+
) from None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from django.http import HttpRequest
|
|
30
|
+
|
|
31
|
+
from jsonrpc_framework.logic.validator import BatchType, RequestType
|
|
32
|
+
from jsonrpc_framework.core.models import MethodType
|
|
33
|
+
from jsonrpc_framework.logic.dispatcher import (
|
|
34
|
+
BatchResponseType,
|
|
35
|
+
HandlerType,
|
|
36
|
+
ResponseType,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
__all__ = ["enable_prometheus", "reset_prometheus", "MetricsView"]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
_enabled: bool = False
|
|
43
|
+
_registry: CollectorRegistry | None = None
|
|
44
|
+
_original_dispatch_single = None
|
|
45
|
+
_original_dispatch = None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def enable_prometheus(*, registry: CollectorRegistry | None = None) -> None:
|
|
49
|
+
global _enabled, _registry, _original_dispatch_single, _original_dispatch
|
|
50
|
+
|
|
51
|
+
if _enabled:
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
if registry is None:
|
|
55
|
+
registry = REGISTRY
|
|
56
|
+
|
|
57
|
+
_registry = registry
|
|
58
|
+
|
|
59
|
+
requests_total = Counter(
|
|
60
|
+
"jsonrpc_requests_total",
|
|
61
|
+
"Total JSON-RPC requests",
|
|
62
|
+
labelnames=("method", "result"),
|
|
63
|
+
registry=_registry,
|
|
64
|
+
)
|
|
65
|
+
request_duration = Histogram(
|
|
66
|
+
"jsonrpc_request_duration_seconds",
|
|
67
|
+
"JSON-RPC request duration in seconds",
|
|
68
|
+
labelnames=("method",),
|
|
69
|
+
registry=_registry,
|
|
70
|
+
)
|
|
71
|
+
errors_total = Counter(
|
|
72
|
+
"jsonrpc_errors_total",
|
|
73
|
+
"Total JSON-RPC errors",
|
|
74
|
+
labelnames=("method", "code"),
|
|
75
|
+
registry=_registry,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
_original_dispatch_single = RpcDispatcher._dispatch_single
|
|
79
|
+
_original_dispatch = RpcDispatcher.dispatch
|
|
80
|
+
|
|
81
|
+
_patch_dispatch_single(
|
|
82
|
+
RpcDispatcher,
|
|
83
|
+
requests_total=requests_total,
|
|
84
|
+
request_duration=request_duration,
|
|
85
|
+
errors_total=errors_total,
|
|
86
|
+
)
|
|
87
|
+
_patch_dispatch(
|
|
88
|
+
RpcDispatcher,
|
|
89
|
+
requests_total=requests_total,
|
|
90
|
+
request_duration=request_duration,
|
|
91
|
+
errors_total=errors_total,
|
|
92
|
+
)
|
|
93
|
+
_enabled = True
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def reset_prometheus() -> None:
|
|
97
|
+
global _enabled, _registry
|
|
98
|
+
global _original_dispatch_single, _original_dispatch
|
|
99
|
+
|
|
100
|
+
if _original_dispatch_single is not None:
|
|
101
|
+
setattr(RpcDispatcher, "_dispatch_single", _original_dispatch_single)
|
|
102
|
+
if _original_dispatch is not None:
|
|
103
|
+
setattr(RpcDispatcher, "dispatch", _original_dispatch)
|
|
104
|
+
|
|
105
|
+
_original_dispatch_single = None
|
|
106
|
+
_original_dispatch = None
|
|
107
|
+
_registry = None
|
|
108
|
+
_enabled = False
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _patch_dispatch_single(
|
|
112
|
+
dispatcher: type[RpcDispatcher],
|
|
113
|
+
*,
|
|
114
|
+
requests_total: Counter,
|
|
115
|
+
request_duration: Histogram,
|
|
116
|
+
errors_total: Counter,
|
|
117
|
+
) -> None:
|
|
118
|
+
old = dispatcher._dispatch_single
|
|
119
|
+
|
|
120
|
+
async def patched(
|
|
121
|
+
self: RpcDispatcher,
|
|
122
|
+
request: RequestType,
|
|
123
|
+
registry: dict[MethodType, HandlerType],
|
|
124
|
+
http_request: HttpRequest,
|
|
125
|
+
) -> ResponseType:
|
|
126
|
+
method = request.method
|
|
127
|
+
start = time.perf_counter()
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
result = await old(self, request, registry, http_request)
|
|
131
|
+
except Exception:
|
|
132
|
+
duration = time.perf_counter() - start
|
|
133
|
+
request_duration.labels(method=method).observe(duration)
|
|
134
|
+
requests_total.labels(method=method, result="error").inc()
|
|
135
|
+
raise
|
|
136
|
+
|
|
137
|
+
duration = time.perf_counter() - start
|
|
138
|
+
|
|
139
|
+
_observe_outcome(
|
|
140
|
+
method=method,
|
|
141
|
+
duration=duration,
|
|
142
|
+
result=result,
|
|
143
|
+
requests_total=requests_total,
|
|
144
|
+
request_duration=request_duration,
|
|
145
|
+
errors_total=errors_total,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return result
|
|
149
|
+
|
|
150
|
+
setattr(dispatcher, "_dispatch_single", patched)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _patch_dispatch(
|
|
154
|
+
dispatcher: type[RpcDispatcher],
|
|
155
|
+
*,
|
|
156
|
+
requests_total: Counter,
|
|
157
|
+
request_duration: Histogram,
|
|
158
|
+
errors_total: Counter,
|
|
159
|
+
) -> None:
|
|
160
|
+
old = dispatcher.dispatch
|
|
161
|
+
|
|
162
|
+
async def patched(
|
|
163
|
+
self: RpcDispatcher,
|
|
164
|
+
body: RequestType | BatchType | RpcError,
|
|
165
|
+
registry: dict[MethodType, HandlerType],
|
|
166
|
+
http_request: HttpRequest,
|
|
167
|
+
) -> ResponseType | BatchResponseType:
|
|
168
|
+
if not isinstance(body, RpcError):
|
|
169
|
+
return await old(self, body, registry, http_request)
|
|
170
|
+
|
|
171
|
+
start = time.perf_counter()
|
|
172
|
+
result = await old(self, body, registry, http_request)
|
|
173
|
+
duration = time.perf_counter() - start
|
|
174
|
+
|
|
175
|
+
_observe_outcome(
|
|
176
|
+
method="_invalid",
|
|
177
|
+
duration=duration,
|
|
178
|
+
result=result,
|
|
179
|
+
requests_total=requests_total,
|
|
180
|
+
request_duration=request_duration,
|
|
181
|
+
errors_total=errors_total,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
return result
|
|
185
|
+
|
|
186
|
+
setattr(dispatcher, "dispatch", patched)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def _observe_outcome(
|
|
190
|
+
method: str,
|
|
191
|
+
duration: float,
|
|
192
|
+
result: ResponseType | BatchResponseType,
|
|
193
|
+
requests_total: Counter,
|
|
194
|
+
request_duration: Histogram,
|
|
195
|
+
errors_total: Counter,
|
|
196
|
+
) -> None:
|
|
197
|
+
request_duration.labels(method=method).observe(duration)
|
|
198
|
+
|
|
199
|
+
if result is None:
|
|
200
|
+
result_label = "notification"
|
|
201
|
+
elif isinstance(result, ErrorResponse):
|
|
202
|
+
result_label = "error"
|
|
203
|
+
errors_total.labels(
|
|
204
|
+
method=method,
|
|
205
|
+
code=str(result.error.code),
|
|
206
|
+
).inc()
|
|
207
|
+
else:
|
|
208
|
+
result_label = "success"
|
|
209
|
+
|
|
210
|
+
requests_total.labels(method=method, result=result_label).inc()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class MetricsView(View):
|
|
214
|
+
http_method_names = ["get"]
|
|
215
|
+
|
|
216
|
+
def get(
|
|
217
|
+
self,
|
|
218
|
+
request: HttpRequest,
|
|
219
|
+
*args: tuple[Any],
|
|
220
|
+
**kwargs: dict[str, Any],
|
|
221
|
+
) -> HttpResponse:
|
|
222
|
+
return HttpResponse(
|
|
223
|
+
generate_latest(_active_registry()),
|
|
224
|
+
content_type=CONTENT_TYPE_LATEST,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _active_registry() -> CollectorRegistry:
|
|
229
|
+
return REGISTRY if _registry is None else _registry
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any
|
|
5
|
+
import inspect
|
|
6
|
+
|
|
7
|
+
import sentry_sdk
|
|
8
|
+
from sentry_sdk.integrations import Integration
|
|
9
|
+
from sentry_sdk.utils import (
|
|
10
|
+
capture_internal_exceptions,
|
|
11
|
+
ensure_integration_enabled,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from jsonrpc_framework.logic.dispatcher import RpcDispatcher
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("django.server")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class JsonRpcIntegration(Integration):
|
|
20
|
+
identifier = "jsonrpc"
|
|
21
|
+
origin = "auto.rpc.jsonrpc"
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
capture_internal_errors: bool = True,
|
|
27
|
+
set_transaction_name: bool = True,
|
|
28
|
+
mechanism_handled: bool = True,
|
|
29
|
+
) -> None:
|
|
30
|
+
self.capture_internal_errors = capture_internal_errors
|
|
31
|
+
self.set_transaction_name = set_transaction_name
|
|
32
|
+
self.mechanism_handled = mechanism_handled
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def setup_once() -> None:
|
|
36
|
+
_patch_dispatch_single(RpcDispatcher)
|
|
37
|
+
_patch_call_handler(RpcDispatcher)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _patch_dispatch_single(RpcDispatcher: type) -> None:
|
|
41
|
+
old = getattr(RpcDispatcher, "_dispatch_single")
|
|
42
|
+
|
|
43
|
+
@ensure_integration_enabled(JsonRpcIntegration, old)
|
|
44
|
+
async def patched(
|
|
45
|
+
self: Any,
|
|
46
|
+
request: Any,
|
|
47
|
+
registry: Any,
|
|
48
|
+
http_request: Any,
|
|
49
|
+
) -> Any:
|
|
50
|
+
integration = sentry_sdk.get_client().get_integration(
|
|
51
|
+
JsonRpcIntegration
|
|
52
|
+
)
|
|
53
|
+
method = request.method
|
|
54
|
+
scope = sentry_sdk.get_current_scope()
|
|
55
|
+
|
|
56
|
+
if integration and integration.set_transaction_name:
|
|
57
|
+
scope.set_transaction_name(
|
|
58
|
+
f"jsonrpc.{method}",
|
|
59
|
+
source="custom",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
scope.set_tag("jsonrpc.method", method)
|
|
63
|
+
|
|
64
|
+
if request.id is not None:
|
|
65
|
+
scope.set_tag("jsonrpc.id", str(request.id))
|
|
66
|
+
|
|
67
|
+
with sentry_sdk.start_span(
|
|
68
|
+
op="rpc.server",
|
|
69
|
+
name=method,
|
|
70
|
+
origin=JsonRpcIntegration.origin,
|
|
71
|
+
):
|
|
72
|
+
return await old(self, request, registry, http_request)
|
|
73
|
+
|
|
74
|
+
setattr(RpcDispatcher, "_dispatch_single", patched)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _patch_call_handler(RpcDispatcher: type) -> None:
|
|
78
|
+
old = getattr(RpcDispatcher, "_call_handler")
|
|
79
|
+
|
|
80
|
+
@ensure_integration_enabled(JsonRpcIntegration, old)
|
|
81
|
+
async def patched(
|
|
82
|
+
self: Any,
|
|
83
|
+
handler: Any,
|
|
84
|
+
bound: Any,
|
|
85
|
+
) -> Any:
|
|
86
|
+
try:
|
|
87
|
+
return await old(self, handler, bound)
|
|
88
|
+
except Exception:
|
|
89
|
+
raise
|
|
90
|
+
|
|
91
|
+
@ensure_integration_enabled(JsonRpcIntegration, old)
|
|
92
|
+
async def patched_call_handler(
|
|
93
|
+
self: Any,
|
|
94
|
+
handler: Any,
|
|
95
|
+
bound: Any,
|
|
96
|
+
) -> Any:
|
|
97
|
+
try:
|
|
98
|
+
if bound is None:
|
|
99
|
+
result = handler()
|
|
100
|
+
else:
|
|
101
|
+
result = handler(*bound.args, **bound.kwargs)
|
|
102
|
+
if inspect.isawaitable(result):
|
|
103
|
+
result = await result
|
|
104
|
+
return result
|
|
105
|
+
except Exception as exc:
|
|
106
|
+
integration = sentry_sdk.get_client().get_integration(
|
|
107
|
+
JsonRpcIntegration
|
|
108
|
+
)
|
|
109
|
+
if integration and integration.capture_internal_errors:
|
|
110
|
+
with capture_internal_exceptions():
|
|
111
|
+
sentry_sdk.capture_exception(
|
|
112
|
+
exc,
|
|
113
|
+
hint={
|
|
114
|
+
"mechanism": {
|
|
115
|
+
"type": "jsonrpc",
|
|
116
|
+
"handled": integration.mechanism_handled,
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
logger.exception(exc)
|
|
121
|
+
from jsonrpc_framework.core.error import InternalError
|
|
122
|
+
|
|
123
|
+
return InternalError()
|
|
124
|
+
|
|
125
|
+
setattr(RpcDispatcher, "_call_handler", patched_call_handler)
|
|
@@ -7,7 +7,6 @@ from typing import Any
|
|
|
7
7
|
from django.http import HttpRequest
|
|
8
8
|
|
|
9
9
|
from jsonrpc_framework.core.models import MethodType, ParamType
|
|
10
|
-
from jsonrpc_framework.logic.validator import RequestType, BatchType
|
|
11
10
|
from jsonrpc_framework.core.error import (
|
|
12
11
|
RpcError,
|
|
13
12
|
InternalError,
|
|
@@ -25,20 +24,6 @@ from jsonrpc_framework.controller.auth import (
|
|
|
25
24
|
ANONYMOUS_AUTH,
|
|
26
25
|
)
|
|
27
26
|
|
|
28
|
-
from jsonrpc_framework.core.error import (
|
|
29
|
-
InternalError,
|
|
30
|
-
InvalidParamsError,
|
|
31
|
-
MethodNotFoundError,
|
|
32
|
-
RpcError,
|
|
33
|
-
)
|
|
34
|
-
from jsonrpc_framework.core.models import (
|
|
35
|
-
ErrorResponse,
|
|
36
|
-
MethodType,
|
|
37
|
-
Notification,
|
|
38
|
-
ParamType,
|
|
39
|
-
Request,
|
|
40
|
-
SuccessResponse,
|
|
41
|
-
)
|
|
42
27
|
from jsonrpc_framework.logic.validator import BatchType, RequestType
|
|
43
28
|
|
|
44
29
|
type ResponseType = SuccessResponse | ErrorResponse | None
|
|
@@ -21,18 +21,9 @@ from jsonrpc_framework.openrpc.document.common._example import (
|
|
|
21
21
|
_OpenRpcExampleObjectTD,
|
|
22
22
|
)
|
|
23
23
|
from jsonrpc_framework.openrpc.document.common._link import _OpenRpcLinkObjectTD
|
|
24
|
-
from jsonrpc_framework.openrpc.document.common._error import (
|
|
25
|
-
_OpenRpcErrorObjectTD,
|
|
26
|
-
)
|
|
27
|
-
from jsonrpc_framework.openrpc.document.common._example import (
|
|
28
|
-
_OpenRpcExampleObjectTD,
|
|
29
|
-
)
|
|
30
24
|
from jsonrpc_framework.openrpc.document.common._pairing_object import (
|
|
31
25
|
_OpenRpcExamplePairingObjectTD,
|
|
32
26
|
)
|
|
33
|
-
from jsonrpc_framework.openrpc.document.common._descriptor import (
|
|
34
|
-
_OpenRcpContentDescriptorObjectTD,
|
|
35
|
-
)
|
|
36
27
|
from jsonrpc_framework.openrpc.document.common._tag import _OpenRpcTagTD
|
|
37
28
|
|
|
38
29
|
|
|
@@ -14,16 +14,6 @@ from jsonrpc_framework.openrpc.document.components import OpenRpcComponents
|
|
|
14
14
|
from jsonrpc_framework.openrpc.document.components._components import (
|
|
15
15
|
_OpenRpcComponentsTD,
|
|
16
16
|
)
|
|
17
|
-
from jsonrpc_framework.openrpc.document.common import (
|
|
18
|
-
OpenRpcLinkObject,
|
|
19
|
-
OpenRpcErrorObject,
|
|
20
|
-
OpenRpcExamplePairingObject,
|
|
21
|
-
OpenRcpContentDescriptorObject,
|
|
22
|
-
OpenRpcTag,
|
|
23
|
-
OpenRpcDataSchema,
|
|
24
|
-
OpenRpcExampleObject,
|
|
25
|
-
)
|
|
26
|
-
from jsonrpc_framework.openrpc.document.common import OpenRcpTypeSchema
|
|
27
17
|
|
|
28
18
|
|
|
29
19
|
@pytest.fixture
|
|
@@ -7,13 +7,6 @@ from jsonrpc_framework.openrpc.document.info._info import _OpenRpcInfoTD
|
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
9
|
|
|
10
|
-
from jsonrpc_framework.openrpc.document.info import (
|
|
11
|
-
OpenRpcContact,
|
|
12
|
-
OpenRpcInfo,
|
|
13
|
-
OpenRpcLicense,
|
|
14
|
-
)
|
|
15
|
-
from jsonrpc_framework.openrpc.document.info._info import _OpenRpcInfoTD
|
|
16
|
-
|
|
17
10
|
|
|
18
11
|
@pytest.fixture
|
|
19
12
|
def openrpc_info() -> OpenRpcInfo:
|
|
@@ -22,38 +22,10 @@ from jsonrpc_framework.openrpc.document.info import (
|
|
|
22
22
|
OpenRpcContact,
|
|
23
23
|
OpenRpcLicense,
|
|
24
24
|
)
|
|
25
|
-
from jsonrpc_framework.openrpc.document.method._method import (
|
|
26
|
-
OpenRpcMethod,
|
|
27
|
-
_OpenRpcMethodTD,
|
|
28
|
-
)
|
|
29
|
-
from jsonrpc_framework.openrpc.document.server import (
|
|
30
|
-
OpenRpcServer,
|
|
31
|
-
OpenRpcServerObjectVariable,
|
|
32
|
-
)
|
|
33
25
|
|
|
34
26
|
from jsonrpc_framework.openrpc.builder.builder import OpenRpcBuilder
|
|
35
27
|
from jsonrpc_framework.openrpc.document.common import (
|
|
36
|
-
OpenRcpContentDescriptorObject,
|
|
37
28
|
OpenRcpTypeSchema,
|
|
38
|
-
OpenRpcErrorObject,
|
|
39
|
-
OpenRpcExampleObject,
|
|
40
|
-
OpenRpcExamplePairingObject,
|
|
41
|
-
OpenRpcLinkObject,
|
|
42
|
-
OpenRpcLinkObjectServer,
|
|
43
|
-
OpenRpcTag,
|
|
44
|
-
)
|
|
45
|
-
from jsonrpc_framework.openrpc.document.external_docs import OpenRpcExternalDoc
|
|
46
|
-
from jsonrpc_framework.openrpc.document.info import (
|
|
47
|
-
OpenRpcContact,
|
|
48
|
-
OpenRpcLicense,
|
|
49
|
-
)
|
|
50
|
-
from jsonrpc_framework.openrpc.document.method._method import (
|
|
51
|
-
OpenRpcMethod,
|
|
52
|
-
_OpenRpcMethodTD,
|
|
53
|
-
)
|
|
54
|
-
from jsonrpc_framework.openrpc.document.server import (
|
|
55
|
-
OpenRpcServer,
|
|
56
|
-
OpenRpcServerObjectVariable,
|
|
57
29
|
)
|
|
58
30
|
|
|
59
31
|
|
|
@@ -13,9 +13,7 @@ from jsonrpc_framework.openrpc.document.components._components import (
|
|
|
13
13
|
from jsonrpc_framework.openrpc.document.external_docs import OpenRpcExternalDoc
|
|
14
14
|
from jsonrpc_framework.openrpc.document.info._info import _OpenRpcInfoTD
|
|
15
15
|
from jsonrpc_framework.openrpc.document.method import OpenRpcMethod
|
|
16
|
-
from jsonrpc_framework.openrpc.document.method._method import _OpenRpcMethodTD
|
|
17
16
|
from jsonrpc_framework.openrpc.document.server import OpenRpcServer
|
|
18
|
-
from jsonrpc_framework.openrpc.document.server._server import _OpenRpcServerTD
|
|
19
17
|
|
|
20
18
|
|
|
21
19
|
def test_builder(
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "django-jsonrpc-framework"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Django jsonrpc implementation"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13"
|
|
@@ -16,9 +16,9 @@ dependencies = [
|
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
[project.optional-dependencies]
|
|
19
|
-
jwt = [
|
|
20
|
-
|
|
21
|
-
]
|
|
19
|
+
jwt = ["pyjwt>=2.13.0"]
|
|
20
|
+
sentry = ["sentry-sdk>=2.0"]
|
|
21
|
+
prometheus = ["prometheus-client>=0.21"]
|
|
22
22
|
|
|
23
23
|
[dependency-groups]
|
|
24
24
|
dev = [
|
|
File without changes
|
{django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/core/__init__.py
RENAMED
|
File without changes
|
{django_jsonrpc_framework-0.2.0 → django_jsonrpc_framework-0.2.1}/jsonrpc_framework/core/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|