From a78dcc26c07bd98fc043a4ed68a5bfafa7c1d559 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Sat, 9 Jul 2022 12:37:22 +0500 Subject: [PATCH 01/14] added MaybeSet generic type to eliminate boilerplate typing. --- pjrpc/client/backend/kombu.py | 4 +- pjrpc/client/client.py | 10 +- pjrpc/client/integrations/pytest.py | 10 +- pjrpc/common/__init__.py | 3 +- pjrpc/common/common.py | 7 +- pjrpc/common/exceptions.py | 6 +- pjrpc/common/v20.py | 16 +- pjrpc/server/dispatcher.py | 19 +-- pjrpc/server/specs/extractors/__init__.py | 56 +++---- pjrpc/server/specs/extractors/docstring.py | 18 +-- pjrpc/server/specs/extractors/pydantic.py | 6 +- pjrpc/server/specs/openapi.py | 180 ++++++++++----------- pjrpc/server/specs/openrpc.py | 90 +++++------ 13 files changed, 215 insertions(+), 210 deletions(-) diff --git a/pjrpc/client/backend/kombu.py b/pjrpc/client/backend/kombu.py index 1fc33ff..a51ae37 100644 --- a/pjrpc/client/backend/kombu.py +++ b/pjrpc/client/backend/kombu.py @@ -5,7 +5,7 @@ import pjrpc from pjrpc.client import AbstractClient -from pjrpc.common import UNSET, UnsetType +from pjrpc.common import UNSET, MaybeSet, UnsetType logger = logging.getLogger(__package__) @@ -98,7 +98,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A **kwargs, ) - response: Optional[Union[UnsetType, str, Exception]] = UNSET + response: MaybeSet[Union[None, str, Exception]] = UNSET def on_response(message: kombu.Message) -> None: nonlocal response diff --git a/pjrpc/client/client.py b/pjrpc/client/client.py index c768c40..099d7eb 100644 --- a/pjrpc/client/client.py +++ b/pjrpc/client/client.py @@ -7,7 +7,7 @@ from pjrpc import AbstractRequest, AbstractResponse, BatchRequest, BatchResponse, Request, Response, common from pjrpc.client import retry -from pjrpc.common import UNSET, UnsetType, exceptions, generators, v20 +from pjrpc.common import UNSET, MaybeSet, UnsetType, exceptions, generators, v20 from pjrpc.common.typedefs import JsonRpcRequestId, MethodType from .tracer import Tracer @@ -457,7 +457,7 @@ def send( self, request: Request, _trace_ctx: SimpleNamespace = SimpleNamespace(), - _retry_strategy: Union[UnsetType, retry.RetryStrategy] = UNSET, + _retry_strategy: MaybeSet[retry.RetryStrategy] = UNSET, **kwargs: Any, ) -> Optional[Response]: """ @@ -515,7 +515,7 @@ def retried(method: Callable[..., Any]) -> Callable[..., Any]: def wrapper( self: 'AbstractClient', request: AbstractRequest, - _retry_strategy: Union[UnsetType, retry.RetryStrategy] = UNSET, + _retry_strategy: MaybeSet[retry.RetryStrategy] = UNSET, **kwargs: Any, ) -> Optional[AbstractResponse]: """ @@ -589,7 +589,7 @@ async def send( self, request: Request, _trace_ctx: SimpleNamespace = SimpleNamespace(), - _retry_strategy: Union[UnsetType, retry.RetryStrategy] = UNSET, + _retry_strategy: MaybeSet[retry.RetryStrategy] = UNSET, **kwargs: Any, ) -> Optional[Response]: """ @@ -647,7 +647,7 @@ def retried(method: Callable[..., Awaitable[Any]]) -> Callable[..., Any]: async def wrapper( self: 'AbstractClient', request: AbstractRequest, - _retry_strategy: Union[UnsetType, retry.RetryStrategy] = UNSET, + _retry_strategy: MaybeSet[retry.RetryStrategy] = UNSET, **kwargs: Any, ) -> Optional[AbstractResponse]: """ diff --git a/pjrpc/client/integrations/pytest.py b/pjrpc/client/integrations/pytest.py index b61ebc0..a808a2b 100644 --- a/pjrpc/client/integrations/pytest.py +++ b/pjrpc/client/integrations/pytest.py @@ -15,7 +15,7 @@ import pjrpc from pjrpc import Response -from pjrpc.common import UNSET, UnsetType +from pjrpc.common import UNSET, MaybeSet from pjrpc.common.typedefs import JsonRpcParams, JsonRpcRequestId CallType = Dict[Tuple[str, str], unittest.mock.Mock] @@ -75,8 +75,8 @@ def add( self, endpoint: str, method_name: str, - result: UnsetType = UNSET, - error: UnsetType = UNSET, + result: MaybeSet[Any] = UNSET, + error: MaybeSet[Any] = UNSET, id: Optional[JsonRpcRequestId] = None, version: str = '2.0', once: bool = False, @@ -102,8 +102,8 @@ def replace( self, endpoint: str, method_name: str, - result: UnsetType = UNSET, - error: UnsetType = UNSET, + result: MaybeSet[Any] = UNSET, + error: MaybeSet[Any] = UNSET, id: Optional[JsonRpcRequestId] = None, version: str = '2.0', once: bool = False, diff --git a/pjrpc/common/__init__.py b/pjrpc/common/__init__.py index 8d2b05b..4c3e225 100644 --- a/pjrpc/common/__init__.py +++ b/pjrpc/common/__init__.py @@ -4,7 +4,7 @@ """ from . import generators, typedefs -from .common import UNSET, JSONEncoder, UnsetType +from .common import UNSET, JSONEncoder, MaybeSet, UnsetType from .v20 import AbstractRequest, AbstractResponse, BatchRequest, BatchResponse, Request, Response DEFAULT_CONTENT_TYPE = 'application/json' @@ -36,6 +36,7 @@ def set_default_content_type(content_type: str) -> None: 'BatchResponse', 'UNSET', 'UnsetType', + 'MaybeSet', 'JSONEncoder', 'DEFAULT_CONTENT_TYPE', 'REQUEST_CONTENT_TYPES', diff --git a/pjrpc/common/common.py b/pjrpc/common/common.py index 040a79d..a4645d7 100644 --- a/pjrpc/common/common.py +++ b/pjrpc/common/common.py @@ -1,6 +1,6 @@ import json import sys -from typing import Any +from typing import Any, TypeVar, Union if sys.version_info >= (3, 8): from typing import Literal @@ -34,7 +34,10 @@ def __deepcopy__(self, memo: dict) -> 'UnsetType': return self -UNSET = UnsetType() +UNSET: UnsetType = UnsetType() + +MaybeSetType = TypeVar('MaybeSetType') +MaybeSet = Union[UnsetType, MaybeSetType] class JSONEncoder(json.JSONEncoder): diff --git a/pjrpc/common/exceptions.py b/pjrpc/common/exceptions.py index 23701c7..eb37fd6 100644 --- a/pjrpc/common/exceptions.py +++ b/pjrpc/common/exceptions.py @@ -3,11 +3,11 @@ """ import typing -from typing import Any, Dict, Optional, Type, Union +from typing import Any, Dict, Optional, Type from pjrpc.common.typedefs import Json -from .common import UNSET, UnsetType +from .common import UNSET, MaybeSet class BaseError(Exception): @@ -97,7 +97,7 @@ def from_json(cls, json_data: 'Json') -> 'JsonRpcError': def get_error_cls(cls, code: int, default: Type['JsonRpcError']) -> Type['JsonRpcError']: return type(cls).__errors_mapping__.get(code, default) - def __init__(self, code: Optional[int] = None, message: Optional[str] = None, data: Union[UnsetType, Any] = UNSET): + def __init__(self, code: Optional[int] = None, message: Optional[str] = None, data: MaybeSet[Any] = UNSET): assert code or self.code, "code is not provided" assert message or self.message, "message is not provided" diff --git a/pjrpc/common/v20.py b/pjrpc/common/v20.py index 519a260..50c72b7 100644 --- a/pjrpc/common/v20.py +++ b/pjrpc/common/v20.py @@ -6,11 +6,11 @@ import abc import itertools as it import operator as op -from typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type, Union +from typing import Any, Dict, Iterable, Iterator, List, Optional, Set, Tuple, Type from pjrpc.common.typedefs import Json, JsonRpcParams, JsonRpcRequestId -from .common import UNSET, UnsetType +from .common import UNSET, MaybeSet, UnsetType from .exceptions import DeserializationError, IdentityError, JsonRpcError @@ -75,7 +75,7 @@ def result(self) -> Any: @property @abc.abstractmethod - def error(self) -> Union[UnsetType, JsonRpcError]: + def error(self) -> MaybeSet[JsonRpcError]: pass @property @@ -157,8 +157,8 @@ def from_json(cls, json_data: Json, error_cls: Type[JsonRpcError] = JsonRpcError def __init__( self, id: Optional[JsonRpcRequestId], - result: Union[UnsetType, Any] = UNSET, - error: Union[UnsetType, JsonRpcError] = UNSET, + result: MaybeSet[Any] = UNSET, + error: MaybeSet[JsonRpcError] = UNSET, ): assert result is not UNSET or error is not UNSET, "result or error argument must be provided" assert result is UNSET or error is UNSET, "result and error arguments are mutually exclusive" @@ -205,7 +205,7 @@ def result(self) -> Any: return self._result @property - def error(self) -> Union[UnsetType, JsonRpcError]: + def error(self) -> MaybeSet[JsonRpcError]: """ Response error. If the response has succeeded returns :py:data:`pjrpc.common.common.UNSET`. """ @@ -437,7 +437,7 @@ def from_json(cls, json_data: Json, error_cls: Type[JsonRpcError] = JsonRpcError return cls(*(Response.from_json(item) for item in json_data)) - def __init__(self, *responses: Response, error: Union[UnsetType, JsonRpcError] = UNSET, strict: bool = True): + def __init__(self, *responses: Response, error: MaybeSet[JsonRpcError] = UNSET, strict: bool = True): self._responses: List[Response] = [] self._ids: Set[JsonRpcRequestId] = set() self._error = error @@ -479,7 +479,7 @@ def __eq__(self, other: Any) -> bool: ) @property - def error(self) -> Union[UnsetType, JsonRpcError]: + def error(self) -> MaybeSet[JsonRpcError]: """ Response error. If the response has succeeded returns :py:data:`pjrpc.common.common.UNSET`. """ diff --git a/pjrpc/server/dispatcher.py b/pjrpc/server/dispatcher.py index 4aca3bd..10c53f2 100644 --- a/pjrpc/server/dispatcher.py +++ b/pjrpc/server/dispatcher.py @@ -7,7 +7,8 @@ from typing import Type, Union, ValuesView, cast import pjrpc -from pjrpc.common import UNSET, AbstractResponse, BatchRequest, BatchResponse, Request, Response, UnsetType, v20 +from pjrpc.common import UNSET, AbstractResponse, BatchRequest, BatchResponse, MaybeSet, Request, Response, UnsetType +from pjrpc.common import v20 from pjrpc.common.typedefs import JsonRpcParams, MethodType from pjrpc.server import utils from pjrpc.server.typedefs import AsyncErrorHandlerType, AsyncMiddlewareType, ErrorHandlerType, MiddlewareType @@ -382,7 +383,7 @@ def dispatch(self, request_text: str, context: Optional[Any] = None) -> Optional logger.getChild('request').debug("request received: %s", request_text) - response: Union[AbstractResponse, UnsetType] + response: MaybeSet[AbstractResponse] try: request_json = self._json_loader(request_text, cls=self._json_decoder) request: Union[Request, BatchRequest] @@ -416,9 +417,9 @@ def dispatch(self, request_text: str, context: Optional[Any] = None) -> Optional return None - def _handle_request(self, request: Request, context: Optional[Any]) -> Union[UnsetType, Response]: + def _handle_request(self, request: Request, context: Optional[Any]) -> MaybeSet[Response]: try: - HandlerType = Callable[[Request, Optional[Any]], Union[UnsetType, Response]] + HandlerType = Callable[[Request, Optional[Any]], MaybeSet[Response]] handler: HandlerType = self._handle_rpc_request for middleware in reversed(self._middlewares): @@ -442,7 +443,7 @@ def _handle_request(self, request: Request, context: Optional[Any]) -> Union[Uns return self._response_class(id=request.id, error=error) - def _handle_rpc_request(self, request: Request, context: Optional[Any]) -> Union[UnsetType, Response]: + def _handle_rpc_request(self, request: Request, context: Optional[Any]) -> MaybeSet[Response]: result = self._handle_rpc_method(request.method, request.params, context) if request.id is None: return UNSET @@ -518,7 +519,7 @@ async def dispatch(self, request_text: str, context: Optional[Any] = None) -> Op logger.getChild('request').debug("request received: %s", request_text) - response: Union[AbstractResponse, UnsetType] + response: MaybeSet[AbstractResponse] try: request_json = self._json_loader(request_text, cls=self._json_decoder) request: Union[Request, BatchRequest] @@ -554,9 +555,9 @@ async def dispatch(self, request_text: str, context: Optional[Any] = None) -> Op return None - async def _handle_request(self, request: Request, context: Optional[Any]) -> Union[UnsetType, Response]: + async def _handle_request(self, request: Request, context: Optional[Any]) -> MaybeSet[Response]: try: - HandlerType = Callable[[Request, Optional[Any]], Awaitable[Union[UnsetType, Response]]] + HandlerType = Callable[[Request, Optional[Any]], Awaitable[MaybeSet[Response]]] handler: HandlerType = self._handle_rpc_request for middleware in reversed(self._middlewares): @@ -580,7 +581,7 @@ async def _handle_request(self, request: Request, context: Optional[Any]) -> Uni return self._response_class(id=request.id, error=error) - async def _handle_rpc_request(self, request: Request, context: Optional[Any]) -> Union[UnsetType, Response]: + async def _handle_rpc_request(self, request: Request, context: Optional[Any]) -> MaybeSet[Response]: result = await self._handle_rpc_method(request.method, request.params, context) if request.id is None: return UNSET diff --git a/pjrpc/server/specs/extractors/__init__.py b/pjrpc/server/specs/extractors/__init__.py index bdebe04..d8dc695 100644 --- a/pjrpc/server/specs/extractors/__init__.py +++ b/pjrpc/server/specs/extractors/__init__.py @@ -1,9 +1,9 @@ import dataclasses as dc import inspect import itertools as it -from typing import Any, Dict, Iterable, List, Optional, Type, Union +from typing import Any, Dict, Iterable, List, Optional, Type -from pjrpc.common import UNSET, UnsetType +from pjrpc.common import UNSET, MaybeSet, UnsetType from pjrpc.common.exceptions import JsonRpcError from pjrpc.common.typedefs import MethodType @@ -16,10 +16,10 @@ class Schema: schema: Dict[str, Any] required: bool = True - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - deprecated: Union[bool, UnsetType] = UNSET - definitions: Union[Dict[str, Any], UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + deprecated: MaybeSet[bool] = UNSET + definitions: MaybeSet[Dict[str, Any]] = UNSET @dc.dataclass(frozen=True) @@ -31,8 +31,8 @@ class Example: params: Dict[str, Any] result: Any version: str = '2.0' - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -43,9 +43,9 @@ class ErrorExample: code: int message: str - data: Union[Optional[Any], UnsetType] = UNSET - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + data: MaybeSet[Optional[Any]] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -55,8 +55,8 @@ class Tag: """ name: str - description: Union[str, UnsetType] = UNSET - externalDocs: Union[str, UnsetType] = UNSET + description: MaybeSet[str] = UNSET + externalDocs: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -67,12 +67,12 @@ class Error: code: int message: str - data: Union[Dict[str, Any], UnsetType] = UNSET - data_required: Union[bool, UnsetType] = UNSET - title: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - deprecated: Union[bool, UnsetType] = UNSET - definitions: Union[Dict[str, Any], UnsetType] = UNSET + data: MaybeSet[Dict[str, Any]] = UNSET + data_required: MaybeSet[bool] = UNSET + title: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + deprecated: MaybeSet[bool] = UNSET + definitions: MaybeSet[Dict[str, Any]] = UNSET class BaseSchemaExtractor: @@ -94,12 +94,12 @@ def extract_result_schema(self, method: MethodType) -> Schema: return Schema(schema={}) - def extract_description(self, method: MethodType) -> Union[UnsetType, str]: + def extract_description(self, method: MethodType) -> MaybeSet[str]: """ Extracts method description. """ - description: Union[UnsetType, str] + description: MaybeSet[str] if method.__doc__: doc = inspect.cleandoc(method.__doc__) description = '\n'.join(it.takewhile(lambda line: line, doc.split('\n'))) @@ -108,14 +108,14 @@ def extract_description(self, method: MethodType) -> Union[UnsetType, str]: return description - def extract_summary(self, method: MethodType) -> Union[UnsetType, str]: + def extract_summary(self, method: MethodType) -> MaybeSet[str]: """ Extracts method summary. """ description = self.extract_description(method) - summary: Union[UnsetType, str] + summary: MaybeSet[str] if not isinstance(description, UnsetType): summary = description.split('.')[0] else: @@ -127,21 +127,21 @@ def extract_errors_schema( self, method: MethodType, errors: Optional[Iterable[Type[JsonRpcError]]] = None, - ) -> Union[UnsetType, List[Error]]: + ) -> MaybeSet[List[Error]]: """ Extracts method errors schema. """ return UNSET - def extract_tags(self, method: MethodType) -> Union[UnsetType, List[Tag]]: + def extract_tags(self, method: MethodType) -> MaybeSet[List[Tag]]: """ Extracts method tags. """ return UNSET - def extract_examples(self, method: MethodType) -> Union[UnsetType, List[Example]]: + def extract_examples(self, method: MethodType) -> MaybeSet[List[Example]]: """ Extracts method usage examples. """ @@ -152,7 +152,7 @@ def extract_error_examples( self, method: MethodType, errors: Optional[Iterable[Type[JsonRpcError]]] = None, - ) -> Union[UnsetType, List[ErrorExample]]: + ) -> MaybeSet[List[ErrorExample]]: """ Extracts method error examples. """ @@ -162,7 +162,7 @@ def extract_error_examples( for error in errors ] if errors else UNSET - def extract_deprecation_status(self, method: MethodType) -> Union[UnsetType, bool]: + def extract_deprecation_status(self, method: MethodType) -> MaybeSet[bool]: """ Extracts method deprecation status. """ diff --git a/pjrpc/server/specs/extractors/docstring.py b/pjrpc/server/specs/extractors/docstring.py index e2307cd..8c48b17 100644 --- a/pjrpc/server/specs/extractors/docstring.py +++ b/pjrpc/server/specs/extractors/docstring.py @@ -1,8 +1,8 @@ -from typing import Dict, Iterable, List, Optional, Type, Union +from typing import Dict, Iterable, List, Optional, Type import docstring_parser -from pjrpc.common import UNSET, UnsetType, exceptions +from pjrpc.common import UNSET, MaybeSet, exceptions from pjrpc.common.typedefs import MethodType from pjrpc.server.specs.extractors import BaseSchemaExtractor, Error, Example, JsonRpcError, Schema, Tag @@ -50,7 +50,7 @@ def extract_errors_schema( self, method: MethodType, errors: Optional[Iterable[Type[JsonRpcError]]] = None, - ) -> Union[UnsetType, List[Error]]: + ) -> MaybeSet[List[Error]]: errors_schema = [] if method.__doc__: @@ -72,7 +72,7 @@ def extract_errors_schema( return errors_schema or UNSET - def extract_description(self, method: MethodType) -> Union[UnsetType, str]: + def extract_description(self, method: MethodType) -> MaybeSet[str]: if method.__doc__: doc = docstring_parser.parse(method.__doc__) description = doc.long_description or UNSET @@ -81,7 +81,7 @@ def extract_description(self, method: MethodType) -> Union[UnsetType, str]: return description - def extract_summary(self, method: MethodType) -> Union[UnsetType, str]: + def extract_summary(self, method: MethodType) -> MaybeSet[str]: if method.__doc__: doc = docstring_parser.parse(method.__doc__) description = doc.short_description or UNSET @@ -90,14 +90,14 @@ def extract_summary(self, method: MethodType) -> Union[UnsetType, str]: return description - def extract_tags(self, method: MethodType) -> Union[UnsetType, List[Tag]]: + def extract_tags(self, method: MethodType) -> MaybeSet[List[Tag]]: return UNSET - def extract_examples(self, method: MethodType) -> Union[UnsetType, List[Example]]: + def extract_examples(self, method: MethodType) -> MaybeSet[List[Example]]: return UNSET - def extract_deprecation_status(self, method: MethodType) -> Union[UnsetType, bool]: - is_deprecated: Union[UnsetType, bool] + def extract_deprecation_status(self, method: MethodType) -> MaybeSet[bool]: + is_deprecated: MaybeSet[bool] if method.__doc__: doc = docstring_parser.parse(method.__doc__) is_deprecated = bool(doc.deprecation) diff --git a/pjrpc/server/specs/extractors/pydantic.py b/pjrpc/server/specs/extractors/pydantic.py index 02ecbc2..0d0e79b 100644 --- a/pjrpc/server/specs/extractors/pydantic.py +++ b/pjrpc/server/specs/extractors/pydantic.py @@ -1,9 +1,9 @@ import inspect -from typing import Any, Dict, Iterable, List, Optional, Type, Union +from typing import Any, Dict, Iterable, List, Optional, Type import pydantic as pd -from pjrpc.common import UNSET, UnsetType +from pjrpc.common import UNSET, MaybeSet from pjrpc.common.exceptions import JsonRpcError from pjrpc.common.typedefs import MethodType from pjrpc.server.specs.extractors import BaseSchemaExtractor, Error, Schema @@ -83,7 +83,7 @@ def extract_errors_schema( self, method: MethodType, errors: Optional[Iterable[Type[JsonRpcError]]] = None, - ) -> Union[UnsetType, List[Error]]: + ) -> MaybeSet[List[Error]]: if errors: errors_schema = [] for error in errors: diff --git a/pjrpc/server/specs/openapi.py b/pjrpc/server/specs/openapi.py index da64162..bf0f4e5 100644 --- a/pjrpc/server/specs/openapi.py +++ b/pjrpc/server/specs/openapi.py @@ -12,9 +12,9 @@ import functools as ft import pathlib import re -from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple, Type, Union +from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Tuple, Type -from pjrpc.common import UNSET, UnsetType, exceptions +from pjrpc.common import UNSET, MaybeSet, UnsetType, exceptions from pjrpc.common.typedefs import Func from pjrpc.server import Method, utils @@ -123,9 +123,9 @@ class Contact: :param email: the email address of the contact person/organization """ - name: Union[str, UnsetType] = UNSET - url: Union[str, UnsetType] = UNSET - email: Union[str, UnsetType] = UNSET + name: MaybeSet[str] = UNSET + url: MaybeSet[str] = UNSET + email: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -138,7 +138,7 @@ class License: """ name: str - url: Union[str, UnsetType] = UNSET + url: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -156,10 +156,10 @@ class Info: title: str version: str - description: Union[str, UnsetType] = UNSET - contact: Union[Contact, UnsetType] = UNSET - license: Union[License, UnsetType] = UNSET - termsOfService: Union[str, UnsetType] = UNSET + description: MaybeSet[str] = UNSET + contact: MaybeSet[Contact] = UNSET + license: MaybeSet[License] = UNSET + termsOfService: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -173,8 +173,8 @@ class ServerVariable: """ default: str - enum: Union[List[str], UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + enum: MaybeSet[List[str]] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -187,8 +187,8 @@ class Server: """ url: str - description: Union[str, UnsetType] = UNSET - variables: Union[Dict[str, ServerVariable], UnsetType] = UNSET + description: MaybeSet[str] = UNSET + variables: MaybeSet[Dict[str, ServerVariable]] = UNSET @dc.dataclass(frozen=True) @@ -201,7 +201,7 @@ class ExternalDocumentation: """ url: str - description: Union[str, UnsetType] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -216,8 +216,8 @@ class Tag: """ name: str - description: Union[str, UnsetType] = UNSET - externalDocs: Union[ExternalDocumentation, UnsetType] = UNSET + description: MaybeSet[str] = UNSET + externalDocs: MaybeSet[ExternalDocumentation] = UNSET class SecuritySchemeType(str, enum.Enum): @@ -255,7 +255,7 @@ class OAuthFlow: authorizationUrl: str tokenUrl: str scopes: Dict[str, str] - refreshUrl: Union[str, UnsetType] = UNSET + refreshUrl: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -269,10 +269,10 @@ class OAuthFlows: :param authorizationCode: configuration for the OAuth Authorization Code flow """ - implicit: Union[OAuthFlow, UnsetType] = UNSET - password: Union[OAuthFlow, UnsetType] = UNSET - clientCredentials: Union[OAuthFlow, UnsetType] = UNSET - authorizationCode: Union[OAuthFlow, UnsetType] = UNSET + implicit: MaybeSet[OAuthFlow] = UNSET + password: MaybeSet[OAuthFlow] = UNSET + clientCredentials: MaybeSet[OAuthFlow] = UNSET + authorizationCode: MaybeSet[OAuthFlow] = UNSET @dc.dataclass(frozen=True) @@ -292,12 +292,12 @@ class SecurityScheme: type: SecuritySchemeType scheme: str - name: Union[str, UnsetType] = UNSET - location: Union[ApiKeyLocation, UnsetType] = UNSET # `in` field - bearerFormat: Union[str, UnsetType] = UNSET - flows: Union[OAuthFlows, UnsetType] = UNSET - openIdConnectUrl: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + name: MaybeSet[str] = UNSET + location: MaybeSet[ApiKeyLocation] = UNSET # `in` field + bearerFormat: MaybeSet[str] = UNSET + flows: MaybeSet[OAuthFlows] = UNSET + openIdConnectUrl: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET def __post_init__(self) -> None: # `in` field name is not allowed in python @@ -314,7 +314,7 @@ class Components: :param schemas: the definition of input and output data types """ - securitySchemes: Union[Dict[str, SecurityScheme], UnsetType] = UNSET + securitySchemes: MaybeSet[Dict[str, SecurityScheme]] = UNSET schemas: Dict[str, Dict[str, Any]] = dc.field(default_factory=dict) @@ -333,8 +333,8 @@ class MethodExample: params: Dict[str, Any] result: Any version: str = '2.0' - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -349,9 +349,9 @@ class ExampleObject: """ value: Any - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - externalValue: Union[str, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + externalValue: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -364,7 +364,7 @@ class MediaType: """ schema: Dict[str, Any] - examples: Union[Dict[str, ExampleObject], UnsetType] = UNSET + examples: MaybeSet[Dict[str, ExampleObject]] = UNSET @dc.dataclass(frozen=True) @@ -377,7 +377,7 @@ class Response: """ description: str - content: Union[Dict[str, MediaType], UnsetType] = UNSET + content: MaybeSet[Dict[str, MediaType]] = UNSET @dc.dataclass(frozen=True) @@ -391,8 +391,8 @@ class RequestBody: """ content: Dict[str, MediaType] - required: Union[bool, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + required: MaybeSet[bool] = UNSET + description: MaybeSet[str] = UNSET class ParameterLocation(str, enum.Enum): @@ -443,16 +443,16 @@ class Parameter: name: str location: ParameterLocation # `in` field - description: Union[str, UnsetType] = UNSET - required: Union[bool, UnsetType] = UNSET - deprecated: Union[bool, UnsetType] = UNSET - allowEmptyValue: Union[bool, UnsetType] = UNSET - style: Union[StyleType, UnsetType] = UNSET - explode: Union[bool, UnsetType] = UNSET - allowReserved: Union[bool, UnsetType] = UNSET - schema: Union[Dict[str, Any], UnsetType] = UNSET - examples: Union[Dict[str, ExampleObject], UnsetType] = UNSET - content: Union[Dict[str, MediaType], UnsetType] = UNSET + description: MaybeSet[str] = UNSET + required: MaybeSet[bool] = UNSET + deprecated: MaybeSet[bool] = UNSET + allowEmptyValue: MaybeSet[bool] = UNSET + style: MaybeSet[StyleType] = UNSET + explode: MaybeSet[bool] = UNSET + allowReserved: MaybeSet[bool] = UNSET + schema: MaybeSet[Dict[str, Any]] = UNSET + examples: MaybeSet[Dict[str, ExampleObject]] = UNSET + content: MaybeSet[Dict[str, MediaType]] = UNSET def __post_init__(self) -> None: # `in` field name is not allowed in python @@ -477,15 +477,15 @@ class Operation: """ responses: Dict[str, Response] - requestBody: Union[RequestBody, UnsetType] = UNSET - tags: Union[List[str], UnsetType] = UNSET - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - externalDocs: Union[ExternalDocumentation, UnsetType] = UNSET - deprecated: Union[bool, UnsetType] = UNSET - servers: Union[List[Server], UnsetType] = UNSET - security: Union[List[Dict[str, List[str]]], UnsetType] = UNSET - parameters: Union[List[Parameter], UnsetType] = UNSET + requestBody: MaybeSet[RequestBody] = UNSET + tags: MaybeSet[List[str]] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + externalDocs: MaybeSet[ExternalDocumentation] = UNSET + deprecated: MaybeSet[bool] = UNSET + servers: MaybeSet[List[Server]] = UNSET + security: MaybeSet[List[Dict[str, List[str]]]] = UNSET + parameters: MaybeSet[List[Parameter]] = UNSET @dc.dataclass(frozen=True) @@ -498,33 +498,33 @@ class Path: :param servers: an alternative server array to service all operations in this path """ - get: Union[Operation, UnsetType] = UNSET - put: Union[Operation, UnsetType] = UNSET - post: Union[Operation, UnsetType] = UNSET - delete: Union[Operation, UnsetType] = UNSET - options: Union[Operation, UnsetType] = UNSET - head: Union[Operation, UnsetType] = UNSET - patch: Union[Operation, UnsetType] = UNSET - trace: Union[Operation, UnsetType] = UNSET - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - servers: Union[List[Server], UnsetType] = UNSET + get: MaybeSet[Operation] = UNSET + put: MaybeSet[Operation] = UNSET + post: MaybeSet[Operation] = UNSET + delete: MaybeSet[Operation] = UNSET + options: MaybeSet[Operation] = UNSET + head: MaybeSet[Operation] = UNSET + patch: MaybeSet[Operation] = UNSET + trace: MaybeSet[Operation] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + servers: MaybeSet[List[Server]] = UNSET def annotate( - params_schema: Union[Dict[str, Schema], UnsetType] = UNSET, - result_schema: Union[Schema, UnsetType] = UNSET, - errors_schema: Union[List[Error], UnsetType] = UNSET, - errors: Union[List[Type[exceptions.JsonRpcError]], UnsetType] = UNSET, - examples: Union[List[MethodExample], UnsetType] = UNSET, - error_examples: Union[List[ErrorExample], UnsetType] = UNSET, - tags: Union[List[str], UnsetType] = UNSET, - summary: Union[str, UnsetType] = UNSET, - description: Union[str, UnsetType] = UNSET, - external_docs: Union[ExternalDocumentation, UnsetType] = UNSET, - deprecated: Union[bool, UnsetType] = UNSET, - security: Union[List[Dict[str, List[str]]], UnsetType] = UNSET, - parameters: Union[List[Parameter], UnsetType] = UNSET, + params_schema: MaybeSet[Dict[str, Schema]] = UNSET, + result_schema: MaybeSet[Schema] = UNSET, + errors_schema: MaybeSet[List[Error]] = UNSET, + errors: MaybeSet[List[Type[exceptions.JsonRpcError]]] = UNSET, + examples: MaybeSet[List[MethodExample]] = UNSET, + error_examples: MaybeSet[List[ErrorExample]] = UNSET, + tags: MaybeSet[List[str]] = UNSET, + summary: MaybeSet[str] = UNSET, + description: MaybeSet[str] = UNSET, + external_docs: MaybeSet[ExternalDocumentation] = UNSET, + deprecated: MaybeSet[bool] = UNSET, + security: MaybeSet[List[Dict[str, List[str]]]] = UNSET, + parameters: MaybeSet[List[Parameter]] = UNSET, ) -> Callable[[Func], Func]: """ Adds Open Api specification annotation to the method. @@ -592,21 +592,21 @@ class OpenAPI(Specification): info: Info paths: Dict[str, Path] components: Components - servers: Union[List[Server], UnsetType] = UNSET - externalDocs: Union[ExternalDocumentation, UnsetType] = UNSET - tags: Union[List[Tag], UnsetType] = UNSET - security: Union[List[Dict[str, List[str]]], UnsetType] = UNSET + servers: MaybeSet[List[Server]] = UNSET + externalDocs: MaybeSet[ExternalDocumentation] = UNSET + tags: MaybeSet[List[Tag]] = UNSET + security: MaybeSet[List[Dict[str, List[str]]]] = UNSET openapi: str = '3.0.0' def __init__( self, info: Info, path: str = '/openapi.json', - servers: Union[List[Server], UnsetType] = UNSET, - external_docs: Union[ExternalDocumentation, UnsetType] = UNSET, - tags: Union[List[Tag], UnsetType] = UNSET, - security: Union[List[Dict[str, List[str]]], UnsetType] = UNSET, - security_schemes: Union[Dict[str, SecurityScheme], UnsetType] = UNSET, + servers: MaybeSet[List[Server]] = UNSET, + external_docs: MaybeSet[ExternalDocumentation] = UNSET, + tags: MaybeSet[List[Tag]] = UNSET, + security: MaybeSet[List[Dict[str, List[str]]]] = UNSET, + security_schemes: MaybeSet[Dict[str, SecurityScheme]] = UNSET, openapi: str = '3.0.0', schema_extractor: Optional[extractors.BaseSchemaExtractor] = None, schema_extractors: Iterable[extractors.BaseSchemaExtractor] = (), diff --git a/pjrpc/server/specs/openrpc.py b/pjrpc/server/specs/openrpc.py index aa0bec8..922b021 100644 --- a/pjrpc/server/specs/openrpc.py +++ b/pjrpc/server/specs/openrpc.py @@ -11,7 +11,7 @@ import itertools as it from typing import Any, Callable, Dict, Iterable, List, Mapping, Optional, Type, Union -from pjrpc.common import UNSET, UnsetType, exceptions +from pjrpc.common import UNSET, MaybeSet, UnsetType, exceptions from pjrpc.common.typedefs import Func from pjrpc.server import Method, utils @@ -30,9 +30,9 @@ class Contact: :param email: the email address of the contact person/organization """ - name: Union[str, UnsetType] = UNSET - url: Union[str, UnsetType] = UNSET - email: Union[str, UnsetType] = UNSET + name: MaybeSet[str] = UNSET + url: MaybeSet[str] = UNSET + email: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -45,7 +45,7 @@ class License: """ name: str - url: Union[str, UnsetType] = UNSET + url: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -63,10 +63,10 @@ class Info: title: str version: str - description: Union[str, UnsetType] = UNSET - contact: Union[Contact, UnsetType] = UNSET - license: Union[License, UnsetType] = UNSET - termsOfService: Union[str, UnsetType] = UNSET + description: MaybeSet[str] = UNSET + contact: MaybeSet[Contact] = UNSET + license: MaybeSet[License] = UNSET + termsOfService: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -82,8 +82,8 @@ class Server: name: str url: str - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -96,7 +96,7 @@ class ExternalDocumentation: """ url: str - description: Union[str, UnsetType] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -112,9 +112,9 @@ class Tag: """ name: str - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - externalDocs: Union[ExternalDocumentation, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + externalDocs: MaybeSet[ExternalDocumentation] = UNSET @dc.dataclass(frozen=True) @@ -130,8 +130,8 @@ class ExampleObject: value: Json name: str - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -149,8 +149,8 @@ class MethodExample: name: str params: List[ExampleObject] result: ExampleObject - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET @dc.dataclass(frozen=True) @@ -170,10 +170,10 @@ class ContentDescriptor: name: str schema: Dict[str, Any] - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - required: Union[bool, UnsetType] = UNSET - deprecated: Union[bool, UnsetType] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + required: MaybeSet[bool] = UNSET + deprecated: MaybeSet[bool] = UNSET @dc.dataclass(frozen=True) @@ -188,7 +188,7 @@ class Error: code: int message: str - data: Union[Dict[str, Any], UnsetType] = UNSET + data: MaybeSet[Dict[str, Any]] = UNSET class ParamStructure(str, enum.Enum): @@ -223,15 +223,15 @@ class MethodInfo: name: str params: List[Union[ContentDescriptor, dict]] result: Union[ContentDescriptor, dict] - errors: Union[List[Error], UnsetType] = UNSET - paramStructure: Union[ParamStructure, UnsetType] = UNSET - examples: Union[List[MethodExample], UnsetType] = UNSET - summary: Union[str, UnsetType] = UNSET - description: Union[str, UnsetType] = UNSET - tags: Union[List[Tag], UnsetType] = UNSET - deprecated: Union[bool, UnsetType] = UNSET - externalDocs: Union[ExternalDocumentation, UnsetType] = UNSET - servers: Union[List[Server], UnsetType] = UNSET + errors: MaybeSet[List[Error]] = UNSET + paramStructure: MaybeSet[ParamStructure] = UNSET + examples: MaybeSet[List[MethodExample]] = UNSET + summary: MaybeSet[str] = UNSET + description: MaybeSet[str] = UNSET + tags: MaybeSet[List[Tag]] = UNSET + deprecated: MaybeSet[bool] = UNSET + externalDocs: MaybeSet[ExternalDocumentation] = UNSET + servers: MaybeSet[List[Server]] = UNSET @dc.dataclass(frozen=True) @@ -246,14 +246,14 @@ class Components: def annotate( - params_schema: Union[List[ContentDescriptor], UnsetType] = UNSET, - result_schema: Union[ContentDescriptor, UnsetType] = UNSET, - errors: Union[List[Union[Error, Type[exceptions.JsonRpcError]]], UnsetType] = UNSET, - examples: Union[List[MethodExample], UnsetType] = UNSET, - summary: Union[str, UnsetType] = UNSET, - description: Union[str, UnsetType] = UNSET, - tags: Union[List[Union[Tag, str]], UnsetType] = UNSET, - deprecated: Union[bool, UnsetType] = UNSET, + params_schema: MaybeSet[List[ContentDescriptor]] = UNSET, + result_schema: MaybeSet[ContentDescriptor] = UNSET, + errors: MaybeSet[List[Union[Error, Type[exceptions.JsonRpcError]]]] = UNSET, + examples: MaybeSet[List[MethodExample]] = UNSET, + summary: MaybeSet[str] = UNSET, + description: MaybeSet[str] = UNSET, + tags: MaybeSet[List[Union[Tag, str]]] = UNSET, + deprecated: MaybeSet[bool] = UNSET, ) -> Callable[[Func], Func]: """ Adds JSON-RPC method to the API specification. @@ -310,16 +310,16 @@ class OpenRPC(Specification): info: Info components: Components methods: List[MethodInfo] = dc.field(default_factory=list) - servers: Union[List[Server], UnsetType] = UNSET - externalDocs: Union[ExternalDocumentation, UnsetType] = UNSET + servers: MaybeSet[List[Server]] = UNSET + externalDocs: MaybeSet[ExternalDocumentation] = UNSET openrpc: str = '1.0.0' def __init__( self, info: Info, path: str = '/openrpc.json', - servers: Union[List[Server], UnsetType] = UNSET, - external_docs: Union[ExternalDocumentation, UnsetType] = UNSET, + servers: MaybeSet[List[Server]] = UNSET, + external_docs: MaybeSet[ExternalDocumentation] = UNSET, openrpc: str = '1.0.0', schema_extractor: Optional[extractors.BaseSchemaExtractor] = None, ): From 9aebce58edcd8e3a8f0538d0a9375e2962184998 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Wed, 21 Sep 2022 19:23:50 +0200 Subject: [PATCH 02/14] examples/aio_pika_server.py: new_event_loop() for 3.10/3.11 & mypy fixes --- examples/aio_pika_server.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/aio_pika_server.py b/examples/aio_pika_server.py index 6c129f0..09f2433 100644 --- a/examples/aio_pika_server.py +++ b/examples/aio_pika_server.py @@ -3,6 +3,7 @@ import uuid import aio_pika +from yarl import URL import pjrpc from pjrpc.server.integration import aio_pika as integration @@ -11,13 +12,13 @@ @methods.add -def sum(a, b): +def sum(a: int, b: int) -> int: """RPC method implementing examples/aio_pika_client.py's calls to sum(1, 2) -> 3""" return a + b @methods.add -def tick(): +def tick() -> None: """RPC method implementing examples/aio_pika_client.py's notification 'tick'""" print("examples/aio_pika_server.py: received tick") @@ -29,12 +30,14 @@ def add_user(message: aio_pika.IncomingMessage, user: dict): return {'id': user_id, **user} -executor = integration.Executor('amqp://guest:guest@localhost:5672/v1', queue_name='jsonrpc') +executor = integration.Executor( + broker_url=URL('amqp://guest:guest@localhost:5672/v1'), queue_name='jsonrpc' +) executor.dispatcher.add_methods(methods) if __name__ == "__main__": logging.basicConfig(level=logging.INFO) - loop = asyncio.get_event_loop() + loop = asyncio.new_event_loop() loop.run_until_complete(executor.start()) try: From 5b168b463a68c4e32bc5c7efdcc71b726978ef4f Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Wed, 21 Sep 2022 19:59:57 +0200 Subject: [PATCH 03/14] examples/aio_pika_server.py: Fix example add_user() to not trigger mypy The add_user() example in examples/aio_pika_server.py is not yet used by the example client, so it can be fixed for mypy using dataclasses similar to the example add_user() with dataclasses at the end of README.rst. --- examples/aio_pika_server.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/examples/aio_pika_server.py b/examples/aio_pika_server.py index 09f2433..a2c6e88 100644 --- a/examples/aio_pika_server.py +++ b/examples/aio_pika_server.py @@ -1,6 +1,7 @@ import asyncio import logging import uuid +from dataclasses import dataclass import aio_pika from yarl import URL @@ -8,6 +9,23 @@ import pjrpc from pjrpc.server.integration import aio_pika as integration + +@dataclass +class UserInfo: + """User information dataclass for the add_user example RPC call""" + + username: str + name: str + age: int + + +@dataclass +class AddedUser(UserInfo): + """User information dataclass (with uuid) for the add_user example RPC call""" + + uuid: uuid.UUID + + methods = pjrpc.server.MethodRegistry() @@ -24,10 +42,12 @@ def tick() -> None: @methods.add(context='message') -def add_user(message: aio_pika.IncomingMessage, user: dict): - user_id = uuid.uuid4().hex - - return {'id': user_id, **user} +def add_user(message: aio_pika.IncomingMessage, user_info: UserInfo) -> AddedUser: + """Simluate the creation of a user: Receive user info and return it with an uuid4. + :param UserInfo user_info: user data + :returns: user_info with a randomly generated uuid4 added + :rtype: AddedUser""" + return AddedUser(**user_info.__dict__, uuid=uuid.uuid4()) executor = integration.Executor( @@ -37,6 +57,8 @@ def add_user(message: aio_pika.IncomingMessage, user: dict): if __name__ == "__main__": logging.basicConfig(level=logging.INFO) + logging.info("Example result from a local call to add_user():") + logging.info(add_user(None, UserInfo("username", "firstname lastname", 18))) loop = asyncio.new_event_loop() loop.run_until_complete(executor.start()) From 6003cafd580d72a829aedc9c93484d80cfa43ba9 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Wed, 5 Oct 2022 13:17:45 +0200 Subject: [PATCH 04/14] Fix aio_pika client to never throw AssertionErrors Issue #91 shows an AssertionError when a connected aio_pika client which didn't need to open a result queue calls client.close(). It should be possible to call client.close() also in this case to close the connection to the RabbitMQ server, because when either the client was interrupted, had nothing to do before closing, it, this is the normal state. Also replace the other assertions in the aio_pika client's close() with simple checks which don't abort the function to close any other remaining connection elements or futures which are not properly handled when simply aborting with an assertion. For details and a test case, see issue #91. --- pjrpc/client/backend/aio_pika.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pjrpc/client/backend/aio_pika.py b/pjrpc/client/backend/aio_pika.py index cddc0c8..9a57390 100644 --- a/pjrpc/client/backend/aio_pika.py +++ b/pjrpc/client/backend/aio_pika.py @@ -81,16 +81,16 @@ async def close(self) -> None: Closes current broker connection. """ - assert self._channel is not None, "client is not initialized" - assert self._connection is not None, "client is not initialized" - assert self._result_queue is not None, "client is not initialized" - - if self._consumer_tag: + if self._consumer_tag and self._result_queue: await self._result_queue.cancel(self._consumer_tag) self._consumer_tag = None - await self._channel.close() - await self._connection.close() + if self._channel: + await self._channel.close() + self._channel = None + if self._connection: + await self._connection.close() + self._connection = None for future in self._futures.values(): if future.done(): From 415416d96f96272b66bd0e279056da61503cca1f Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Wed, 5 Oct 2022 14:22:00 +0200 Subject: [PATCH 05/14] skip testing with Python3.7 on github, it's flake8 is broken --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a067c7..2a99384 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10'] + python-version: ['3.8', '3.9', '3.10'] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} From 007ec0775bea3b911729a97ea58f063764c148d7 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:11:53 +0500 Subject: [PATCH 06/14] pre-commit repos updated. --- .pre-commit-config.yaml | 12 ++++++------ pjrpc/client/backend/aio_pika.py | 4 ++-- pjrpc/client/backend/kombu.py | 2 +- pjrpc/server/dispatcher.py | 8 ++++---- pjrpc/server/integration/aiohttp.py | 2 +- pjrpc/server/integration/kombu.py | 4 ++-- pjrpc/server/integration/starlette.py | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9f79ac0..7ecee86 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ default_stages: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.4.0 hooks: - id: check-yaml - id: check-toml @@ -25,25 +25,25 @@ repos: args: - --fix=no - repo: https://github.com/asottile/add-trailing-comma - rev: v2.2.1 + rev: v3.0.0 hooks: - id: add-trailing-comma stages: - commit - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.6.0 + rev: v2.0.2 hooks: - id: autopep8 stages: - commit args: - --diff - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 + - repo: https://github.com/pycqa/flake8 + rev: 6.0.0 hooks: - id: flake8 - repo: https://github.com/pycqa/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort name: fix import order diff --git a/pjrpc/client/backend/aio_pika.py b/pjrpc/client/backend/aio_pika.py index 9a57390..7a77875 100644 --- a/pjrpc/client/backend/aio_pika.py +++ b/pjrpc/client/backend/aio_pika.py @@ -72,7 +72,7 @@ async def connect(self) -> None: if self._result_queue_name: assert channel self._result_queue = await channel.declare_queue( - self._result_queue_name, **(self._result_queue_args or {}) + self._result_queue_name, **(self._result_queue_args or {}), ) self._consumer_tag = await self._result_queue.consume(self._on_result_message, no_ack=True) @@ -132,7 +132,7 @@ async def _request(self, request_text: str, is_notification: bool = False, **kwa async with self._connection.channel() as channel: if not self._result_queue: result_queue = await channel.declare_queue( - request_id, exclusive=True, **(self._result_queue_args or {}) + request_id, exclusive=True, **(self._result_queue_args or {}), ) await result_queue.consume(self._on_result_message, no_ack=True) else: diff --git a/pjrpc/client/backend/kombu.py b/pjrpc/client/backend/kombu.py index a51ae37..9125e72 100644 --- a/pjrpc/client/backend/kombu.py +++ b/pjrpc/client/backend/kombu.py @@ -83,7 +83,7 @@ def _request(self, request_text: str, is_notification: bool = False, **kwargs: A request_id = kombu.uuid() result_queue = self._result_queue or kombu.Queue( - exclusive=True, name=request_id, **(self._result_queue_args or {}) + exclusive=True, name=request_id, **(self._result_queue_args or {}), ) with kombu.Producer(self._connection) as producer: diff --git a/pjrpc/server/dispatcher.py b/pjrpc/server/dispatcher.py index 10c53f2..4dfcde2 100644 --- a/pjrpc/server/dispatcher.py +++ b/pjrpc/server/dispatcher.py @@ -40,7 +40,7 @@ def __init__(self, method: MethodType, name: Optional[str] = None, context: Opti def bind(self, params: Optional['JsonRpcParams'], context: Optional[Any] = None) -> MethodType: method_params = self.validator.validate_method( - self.method, params, exclude=(self.context,) if self.context else (), **self.validator_args + self.method, params, exclude=(self.context,) if self.context else (), **self.validator_args, ) if self.context is not None: @@ -404,7 +404,7 @@ def dispatch(self, request_text: str, context: Optional[Any] = None) -> Optional *( resp for resp in (self._handle_request(request, context) for request in request) if not isinstance(resp, UnsetType) - ) + ), ) else: response = self._handle_request(request, context) @@ -539,9 +539,9 @@ async def dispatch(self, request_text: str, context: Optional[Any] = None) -> Op response = self._batch_response( *filter( lambda resp: resp is not UNSET, await asyncio.gather( - *(self._handle_request(request, context) for request in request) + *(self._handle_request(request, context) for request in request), ), - ) + ), ) else: diff --git a/pjrpc/server/integration/aiohttp.py b/pjrpc/server/integration/aiohttp.py index e328336..9d32f37 100644 --- a/pjrpc/server/integration/aiohttp.py +++ b/pjrpc/server/integration/aiohttp.py @@ -27,7 +27,7 @@ def __init__( path: str = '', spec: Optional[specs.Specification] = None, app: Optional[web.Application] = None, - **kwargs: Any + **kwargs: Any, ): self._path = path.rstrip('/') self._spec = spec diff --git a/pjrpc/server/integration/kombu.py b/pjrpc/server/integration/kombu.py index 1241600..dbacfed 100644 --- a/pjrpc/server/integration/kombu.py +++ b/pjrpc/server/integration/kombu.py @@ -34,7 +34,7 @@ def __init__( queue_args: Optional[Dict[str, Any]] = None, publish_args: Optional[Dict[str, Any]] = None, prefetch_count: int = 0, - **kwargs: Any + **kwargs: Any, ): self.connection = kombu.Connection(broker_url, **(conn_args or {})) @@ -84,7 +84,7 @@ def _rpc_handle(self, message: kombu.Message) -> None: correlation_id=message.properties.get('correlation_id'), content_type=pjrpc.common.DEFAULT_CONTENT_TYPE, content_encoding='utf8', - **(self._publish_args or {}) + **(self._publish_args or {}), ) message.ack() diff --git a/pjrpc/server/integration/starlette.py b/pjrpc/server/integration/starlette.py index 82645da..1edad88 100644 --- a/pjrpc/server/integration/starlette.py +++ b/pjrpc/server/integration/starlette.py @@ -39,7 +39,7 @@ def __init__( path: str = '', spec: Optional[specs.Specification] = None, app: Optional[Starlette] = None, - **kwargs: Any + **kwargs: Any, ): self._path = path.rstrip('/') self._spec = spec From 4802be28d58c501dbba7b8d29c41a11712999cc0 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:16:39 +0500 Subject: [PATCH 07/14] mypy version updated. --- .pre-commit-config.yaml | 2 +- pjrpc/client/client.py | 10 ++++----- pjrpc/client/integrations/pytest.py | 8 +++---- pjrpc/common/common.py | 4 ++-- pjrpc/common/exceptions.py | 4 ++-- pjrpc/common/v20.py | 4 ++-- pjrpc/server/dispatcher.py | 26 +++++++++++----------- pjrpc/server/integration/werkzeug.py | 4 ++-- pjrpc/server/specs/__init__.py | 8 ++++--- pjrpc/server/specs/extractors/docstring.py | 8 +++---- pjrpc/server/specs/extractors/pydantic.py | 2 +- pjrpc/server/specs/openapi.py | 2 +- pjrpc/server/specs/openrpc.py | 6 ++--- pjrpc/server/validators/pydantic.py | 2 +- pyproject.toml | 3 ++- 15 files changed, 48 insertions(+), 45 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7ecee86..02df39d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -63,7 +63,7 @@ repos: - --multi-line=9 - --project=pjrpc - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.942 + rev: v1.4.1 hooks: - id: mypy stages: diff --git a/pjrpc/client/client.py b/pjrpc/client/client.py index 099d7eb..00d70a6 100644 --- a/pjrpc/client/client.py +++ b/pjrpc/client/client.py @@ -67,7 +67,7 @@ def __init__(self, client: 'BaseAbstractClient'): self._id_gen = client.id_gen_impl() self._requests = client.batch_request_class() - def __getitem__(self, requests: Iterable[Tuple]) -> Union[Awaitable[Any], Any]: + def __getitem__(self, requests: Iterable[Tuple[Any]]) -> Union[Awaitable[Any], Any]: """ Adds requests to the batch and makes a request. @@ -80,7 +80,7 @@ def __getitem__(self, requests: Iterable[Tuple]) -> Union[Awaitable[Any], Any]: method=method, params=params, id=next(self._id_gen), - ) for method, *params in requests + ) for method, *params in requests # type: ignore[var-annotated] ]) return self.call() @@ -287,7 +287,7 @@ class Proxy: def __init__(self, client: 'BaseAbstractClient'): self._client = client - def __getattr__(self, attr: str) -> Callable: + def __getattr__(self, attr: str) -> Callable[..., Any]: return ft.partial(self._client.call, attr) def __init__( @@ -298,8 +298,8 @@ def __init__( batch_response_class: Type[BatchResponse] = v20.BatchResponse, error_cls: Type[exceptions.JsonRpcError] = exceptions.JsonRpcError, id_gen_impl: Callable[..., Generator[JsonRpcRequestId, None, None]] = generators.sequential, - json_loader: Callable = json.loads, - json_dumper: Callable = json.dumps, + json_loader: Callable[..., Any] = json.loads, + json_dumper: Callable[..., str] = json.dumps, json_encoder: Type[common.JSONEncoder] = common.JSONEncoder, json_decoder: Optional[json.JSONDecoder] = None, strict: bool = True, diff --git a/pjrpc/client/integrations/pytest.py b/pjrpc/client/integrations/pytest.py index a808a2b..9640139 100644 --- a/pjrpc/client/integrations/pytest.py +++ b/pjrpc/client/integrations/pytest.py @@ -33,7 +33,7 @@ def __init__( version: str, method_name: str, once: bool, - callback: Optional[Callable], + callback: Optional[Callable[..., Any]], **response_data: Any, ): self.endpoint = endpoint @@ -80,7 +80,7 @@ def add( id: Optional[JsonRpcRequestId] = None, version: str = '2.0', once: bool = False, - callback: Optional[Callable] = None, + callback: Optional[Callable[..., Any]] = None, ) -> None: """ Appends response patch. If the same method patch already exists they will be used in a round-robin way. @@ -107,7 +107,7 @@ def replace( id: Optional[JsonRpcRequestId] = None, version: str = '2.0', once: bool = False, - callback: Optional[Callable] = None, + callback: Optional[Callable[..., Any]] = None, idx: int = 0, ) -> None: """ @@ -175,7 +175,7 @@ def start(self) -> Any: if asyncio.iscoroutinefunction(patcher.temp_original): self._async_resp = True - side_effect: Callable + side_effect: Callable[..., Any] if self._async_resp: async def side_effect(*args: Any, **kwargs: Any) -> str: return await self._on_request(*args, **kwargs) diff --git a/pjrpc/common/common.py b/pjrpc/common/common.py index a4645d7..21d533a 100644 --- a/pjrpc/common/common.py +++ b/pjrpc/common/common.py @@ -1,6 +1,6 @@ import json import sys -from typing import Any, TypeVar, Union +from typing import Any, Dict, TypeVar, Union if sys.version_info >= (3, 8): from typing import Literal @@ -30,7 +30,7 @@ def __str__(self) -> str: def __copy__(self) -> 'UnsetType': return self - def __deepcopy__(self, memo: dict) -> 'UnsetType': + def __deepcopy__(self, memo: Dict[str, Any]) -> 'UnsetType': return self diff --git a/pjrpc/common/exceptions.py b/pjrpc/common/exceptions.py index eb37fd6..1a6d016 100644 --- a/pjrpc/common/exceptions.py +++ b/pjrpc/common/exceptions.py @@ -3,7 +3,7 @@ """ import typing -from typing import Any, Dict, Optional, Type +from typing import Any, Dict, Optional, Tuple, Type from pjrpc.common.typedefs import Json @@ -38,7 +38,7 @@ class JsonRpcErrorMeta(type): __errors_mapping__: Dict[int, Type['JsonRpcError']] = {} - def __new__(mcs, name: str, bases: tuple, dct: dict) -> Type['JsonRpcError']: + def __new__(mcs, name: str, bases: Tuple[type, ...], dct: Dict[str, Any]) -> Type['JsonRpcError']: cls: Type['JsonRpcError'] = typing.cast(Type['JsonRpcError'], super().__new__(mcs, name, bases, dct)) if hasattr(cls, 'code') and cls.code is not None: mcs.__errors_mapping__[cls.code] = cls diff --git a/pjrpc/common/v20.py b/pjrpc/common/v20.py index 50c72b7..23ce3f4 100644 --- a/pjrpc/common/v20.py +++ b/pjrpc/common/v20.py @@ -228,7 +228,7 @@ def is_error(self) -> bool: return not self.is_success - @property + @property # type: ignore[override] def related(self) -> Optional['Request']: """ Returns the request related response object if the response has been @@ -531,7 +531,7 @@ def result(self) -> Tuple[Any, ...]: return tuple(result) - @property + @property # type: ignore[override] def related(self) -> Optional['BatchRequest']: """ Returns the request related response object if the response has been diff --git a/pjrpc/server/dispatcher.py b/pjrpc/server/dispatcher.py index 4dfcde2..c8b687c 100644 --- a/pjrpc/server/dispatcher.py +++ b/pjrpc/server/dispatcher.py @@ -106,7 +106,7 @@ def __init__(self, context: Optional[Any] = None): pass @classmethod - def __methods__(cls) -> Generator[Callable, None, None]: + def __methods__(cls) -> Generator[Callable[..., Any], None, None]: for attr_name in filter(lambda name: not name.startswith('_'), dir(cls)): attr = getattr(cls, attr_name) if callable(attr): @@ -184,7 +184,7 @@ def decorator(method: MethodType) -> MethodType: else: return decorator(maybe_method) - def add_methods(self, *methods: Union[Callable, Method]) -> None: + def add_methods(self, *methods: Union[Callable[..., Any], Method]) -> None: """ Adds methods to the registry. @@ -200,7 +200,7 @@ def add_methods(self, *methods: Union[Callable, Method]) -> None: def view( self, maybe_view: Optional[Type[ViewMixin]] = None, context: Optional[Any] = None, prefix: Optional[str] = None, - ) -> Union[ViewMixin, Callable]: + ) -> Union[ViewMixin, Callable[..., Any]]: """ Methods view decorator. @@ -279,12 +279,12 @@ def __init__( response_class: Type[Response] = v20.Response, batch_request: Type[BatchRequest] = v20.BatchRequest, batch_response: Type[BatchResponse] = v20.BatchResponse, - json_loader: Callable = json.loads, - json_dumper: Callable = json.dumps, + json_loader: Callable[..., Any] = json.loads, + json_dumper: Callable[..., str] = json.dumps, json_encoder: Type[JSONEncoder] = JSONEncoder, json_decoder: Optional[Type[json.JSONDecoder]] = None, - middlewares: Iterable[Callable] = (), - error_handlers: Dict[Union[None, int, Exception], List[Callable]] = {}, + middlewares: Iterable[Callable[..., Any]] = (), + error_handlers: Dict[Union[None, int, Exception], List[Callable[..., Any]]] = {}, ): self._json_loader = json_loader self._json_dumper = json_dumper @@ -303,7 +303,7 @@ def __init__( def registry(self) -> MethodRegistry: return self._registry - def add(self, method: Callable, name: Optional[str] = None, context: Optional[Any] = None) -> None: + def add(self, method: Callable[..., Any], name: Optional[str] = None, context: Optional[Any] = None) -> None: """ Adds method to the registry. @@ -314,7 +314,7 @@ def add(self, method: Callable, name: Optional[str] = None, context: Optional[An self._registry.add(method, name, context) - def add_methods(self, *methods: Union[MethodRegistry, Method, Callable]) -> None: + def add_methods(self, *methods: Union[MethodRegistry, Method, Callable[..., Any]]) -> None: """ Adds methods to the registry. @@ -352,8 +352,8 @@ def __init__( response_class: Type[Response] = v20.Response, batch_request: Type[BatchRequest] = v20.BatchRequest, batch_response: Type[BatchResponse] = v20.BatchResponse, - json_loader: Callable = json.loads, - json_dumper: Callable = json.dumps, + json_loader: Callable[..., Any] = json.loads, + json_dumper: Callable[..., str] = json.dumps, json_encoder: Type[JSONEncoder] = JSONEncoder, json_decoder: Optional[Type[json.JSONDecoder]] = None, middlewares: Iterable['MiddlewareType'] = (), @@ -488,8 +488,8 @@ def __init__( response_class: Type[Response] = v20.Response, batch_request: Type[BatchRequest] = v20.BatchRequest, batch_response: Type[BatchResponse] = v20.BatchResponse, - json_loader: Callable = json.loads, - json_dumper: Callable = json.dumps, + json_loader: Callable[..., Any] = json.loads, + json_dumper: Callable[..., str] = json.dumps, json_encoder: Type[JSONEncoder] = JSONEncoder, json_decoder: Optional[Type[json.JSONDecoder]] = None, middlewares: Iterable['AsyncMiddlewareType'] = (), diff --git a/pjrpc/server/integration/werkzeug.py b/pjrpc/server/integration/werkzeug.py index ea53909..6c548ee 100644 --- a/pjrpc/server/integration/werkzeug.py +++ b/pjrpc/server/integration/werkzeug.py @@ -18,10 +18,10 @@ def __init__(self, path: str = '', **kwargs: Any): self._path = path self._dispatcher = pjrpc.server.Dispatcher(**kwargs) - def __call__(self, environ: Dict[str, Any], start_response: Callable) -> Iterable[bytes]: + def __call__(self, environ: Dict[str, Any], start_response: Callable[..., Any]) -> Iterable[bytes]: return self.wsgi_app(environ, start_response) - def wsgi_app(self, environ: Dict[str, Any], start_response: Callable) -> Iterable[bytes]: + def wsgi_app(self, environ: Dict[str, Any], start_response: Callable[..., Any]) -> Iterable[bytes]: environ['app'] = self request = werkzeug.Request(environ) response = self._rpc_handle(request) diff --git a/pjrpc/server/specs/__init__.py b/pjrpc/server/specs/__init__.py index 78c958d..df5626e 100644 --- a/pjrpc/server/specs/__init__.py +++ b/pjrpc/server/specs/__init__.py @@ -1,7 +1,7 @@ import abc import enum import json -from typing import Any, Iterable, Mapping, Optional +from typing import Any, Dict, Iterable, Mapping, Optional from pjrpc.server import Method @@ -18,16 +18,18 @@ def default(self, o: Any) -> Any: return super().default(o) -class BaseUI: +class BaseUI(abc.ABC): """ Base UI. """ + @abc.abstractmethod def get_static_folder(self) -> str: """ Returns ui statics folder. """ + @abc.abstractmethod def get_index_page(self, spec_url: str) -> str: """ Returns ui index webpage. @@ -80,7 +82,7 @@ def schema( path: str, methods: Iterable[Method] = (), methods_map: Mapping[str, Iterable[Method]] = {}, - ) -> dict: + ) -> Dict[str, Any]: """ Returns specification schema. diff --git a/pjrpc/server/specs/extractors/docstring.py b/pjrpc/server/specs/extractors/docstring.py index 8c48b17..f0162e6 100644 --- a/pjrpc/server/specs/extractors/docstring.py +++ b/pjrpc/server/specs/extractors/docstring.py @@ -25,8 +25,8 @@ def extract_params_schema(self, method: MethodType, exclude: Iterable[str] = ()) parameters_schema[param.arg_name] = Schema( schema={'type': param.type_name}, required=not param.is_optional, - summary=param.description.split('.')[0], - description=param.description, + summary=param.description.split('.')[0] if param.description is not None else UNSET, + description=param.description if param.description is not None else UNSET, ) return parameters_schema @@ -40,8 +40,8 @@ def extract_result_schema(self, method: MethodType) -> Schema: result_schema = Schema( schema={'type': doc.returns.type_name}, required=True, - summary=doc.returns.description.split('.')[0], - description=doc.returns.description, + summary=doc.returns.description.split('.')[0] if doc.returns.description is not None else UNSET, + description=doc.returns.description if doc.returns.description is not None else UNSET, ) return result_schema diff --git a/pjrpc/server/specs/extractors/pydantic.py b/pjrpc/server/specs/extractors/pydantic.py index 0d0e79b..aa300f9 100644 --- a/pjrpc/server/specs/extractors/pydantic.py +++ b/pjrpc/server/specs/extractors/pydantic.py @@ -126,7 +126,7 @@ def _extract_field_schema(model_schema: Dict[str, Any], field_name: str) -> Dict return field_schema @staticmethod - def _get_annotations(cls: Type) -> Dict[str, Any]: + def _get_annotations(cls: Type[Any]) -> Dict[str, Any]: annotations: Dict[str, Any] = {} for patent in cls.mro(): annotations.update(**getattr(patent, '__annotations__', {})) diff --git a/pjrpc/server/specs/openapi.py b/pjrpc/server/specs/openapi.py index bf0f4e5..3d8972f 100644 --- a/pjrpc/server/specs/openapi.py +++ b/pjrpc/server/specs/openapi.py @@ -631,7 +631,7 @@ def schema( path: str, methods: Iterable[Method] = (), methods_map: Mapping[str, Iterable[Method]] = {}, - ) -> dict: + ) -> Dict[str, Any]: methods_list: List[Tuple[str, Method]] = [] methods_list.extend((path, method) for method in methods) methods_list.extend( diff --git a/pjrpc/server/specs/openrpc.py b/pjrpc/server/specs/openrpc.py index 922b021..43a4dba 100644 --- a/pjrpc/server/specs/openrpc.py +++ b/pjrpc/server/specs/openrpc.py @@ -17,7 +17,7 @@ from . import Specification, extractors -Json = Union[str, int, float, dict, bool, list, tuple, set, None] +Json = Union[str, int, float, dict, bool, list, tuple, set, None] # type: ignore[type-arg] @dc.dataclass(frozen=True) @@ -221,8 +221,8 @@ class MethodInfo: """ name: str - params: List[Union[ContentDescriptor, dict]] - result: Union[ContentDescriptor, dict] + params: List[Union[ContentDescriptor, Dict[str, Any]]] + result: Union[ContentDescriptor, Dict[str, Any]] errors: MaybeSet[List[Error]] = UNSET paramStructure: MaybeSet[ParamStructure] = UNSET examples: MaybeSet[List[MethodExample]] = UNSET diff --git a/pjrpc/server/validators/pydantic.py b/pjrpc/server/validators/pydantic.py index a413e2b..6d107d5 100644 --- a/pjrpc/server/validators/pydantic.py +++ b/pjrpc/server/validators/pydantic.py @@ -27,7 +27,7 @@ def __init__(self, coerce: bool = True, **config_args: Any): self._model_config = type('ModelConfig', (pydantic.BaseConfig,), config_args) def validate_method( - self, method: Callable, params: Optional['JsonRpcParams'], exclude: Iterable[str] = (), **kwargs: Any, + self, method: Callable[..., Any], params: Optional['JsonRpcParams'], exclude: Iterable[str] = (), **kwargs: Any, ) -> Dict[str, Any]: """ Validates params against method using ``pydantic`` validator. diff --git a/pyproject.toml b/pyproject.toml index aba2b6f..8f4c879 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,7 +79,7 @@ pytest-cov = "^2.0" pytest-mock = "^1.0" responses = "^0.14" respx = "^0.19.2" -mypy = "^0.942" +mypy = "^1.4.1" pre-commit = "^2.19" [build-system] @@ -88,6 +88,7 @@ build-backend = "poetry.core.masonry.api" [tool.mypy] allow_redefinition = true +disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_decorators = false disallow_untyped_defs = true From a34b4c9caaa094ff8b643d845fe18b82ebac94b8 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:21:18 +0500 Subject: [PATCH 08/14] examples bugs fixed. --- examples/httpserver.py | 7 ++++--- examples/openapi_aiohttp.py | 14 ++++++++++++++ examples/openapi_aiohttp_subendpoints.py | 16 ++++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/examples/httpserver.py b/examples/httpserver.py index 98fdf1d..889e039 100644 --- a/examples/httpserver.py +++ b/examples/httpserver.py @@ -18,19 +18,20 @@ def do_POST(self): content_type = self.headers.get('Content-Type') if content_type not in pjrpc.common.REQUEST_CONTENT_TYPES: - self.send_response(http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE) + self.send_error(http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE) return try: content_length = int(self.headers.get('Content-Length', -1)) request_text = self.rfile.read(content_length).decode() except UnicodeDecodeError: - self.send_response(http.HTTPStatus.BAD_REQUEST) + self.send_error(http.HTTPStatus.BAD_REQUEST) return response_text = self.server.dispatcher.dispatch(request_text, context=self) if response_text is None: - self.send_response(http.HTTPStatus.OK) + self.send_response_only(http.HTTPStatus.OK) + self.end_headers() else: self.send_response(http.HTTPStatus.OK) self.send_header("Content-type", pjrpc.common.DEFAULT_CONTENT_TYPE) diff --git a/examples/openapi_aiohttp.py b/examples/openapi_aiohttp.py index 21e14d0..2538c0e 100644 --- a/examples/openapi_aiohttp.py +++ b/examples/openapi_aiohttp.py @@ -1,6 +1,7 @@ import uuid from typing import Any +import aiohttp_cors import pydantic from aiohttp import helpers, web @@ -220,5 +221,18 @@ def delete_user(request: web.Request, user_id: uuid.UUID) -> None: jsonrpc_app.dispatcher.add_methods(methods) app.add_subapp('/myapp', jsonrpc_app.app) +cors = aiohttp_cors.setup( + app, defaults={ + '*': aiohttp_cors.ResourceOptions( + allow_credentials=True, + expose_headers='*', + allow_headers='*', + ), + }, +) +for route in list(app.router.routes()): + cors.add(route) + + if __name__ == "__main__": web.run_app(app, host='localhost', port=8080) diff --git a/examples/openapi_aiohttp_subendpoints.py b/examples/openapi_aiohttp_subendpoints.py index 2c2bd71..a24ada3 100644 --- a/examples/openapi_aiohttp_subendpoints.py +++ b/examples/openapi_aiohttp_subendpoints.py @@ -1,6 +1,7 @@ import uuid from typing import Any +import aiohttp_cors import pydantic from aiohttp import web @@ -15,8 +16,6 @@ post_methods = pjrpc.server.MethodRegistry() validator = validators.PydanticValidator() -credentials = {"admin": "admin"} - class JSONEncoder(pjrpc.JSONEncoder): def default(self, o: Any) -> Any: @@ -185,5 +184,18 @@ def add_post(request: web.Request, post: PostIn) -> PostOut: jsonrpc_app.add_endpoint('/posts', json_encoder=JSONEncoder).add_methods(post_methods) +cors = aiohttp_cors.setup( + jsonrpc_app.app, defaults={ + '*': aiohttp_cors.ResourceOptions( + allow_credentials=True, + expose_headers='*', + allow_headers='*', + ), + }, +) +for route in list(jsonrpc_app.app.router.routes()): + cors.add(route) + + if __name__ == "__main__": web.run_app(jsonrpc_app.app, host='localhost', port=8080) From 8346099f42ec0b2abbb5599423f198d1582a585b Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:22:01 +0500 Subject: [PATCH 09/14] documentation updated. --- .readthedocs.yaml | 2 +- README.rst | 6 +- docs/source/_static/css/custom.css | 8 +-- docs/source/conf.py | 85 +++++++++-------------------- docs/source/index.rst | 10 +++- docs/source/pjrpc/api/client.rst | 3 + docs/source/pjrpc/api/common.rst | 2 + docs/source/pjrpc/api/server.rst | 4 ++ docs/source/pjrpc/client.rst | 2 +- docs/source/pjrpc/extending.rst | 11 ++-- docs/source/pjrpc/specification.rst | 4 +- docs/source/pjrpc/testing.rst | 9 +++ pjrpc/common/generators.py | 9 +++ pyproject.toml | 15 ++++- 14 files changed, 89 insertions(+), 81 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f534918..fae5765 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -15,4 +15,4 @@ python: - method: pip path: . extra_requirements: - - docgen + - docs diff --git a/README.rst b/README.rst index 2bf3ef8..60173d3 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,8 @@ pjrpc .. image:: https://static.pepy.tech/personalized-badge/pjrpc?period=month&units=international_system&left_color=grey&right_color=orange&left_text=Downloads/month :target: https://pepy.tech/project/pjrpc :alt: Downloads/month -.. image:: https://travis-ci.org/dapper91/pjrpc.svg?branch=master - :target: https://travis-ci.org/dapper91/pjrpc +.. image:: https://github.com/dapper91/pjrpc/actions/workflows/test.yml/badge.svg?branch=master + :target: https://github.com/dapper91/pjrpc/actions/workflows/test.yml :alt: Build status .. image:: https://img.shields.io/pypi/l/pjrpc.svg :target: https://pypi.org/project/pjrpc @@ -67,7 +67,7 @@ Extra requirements Documentation ------------- -Documentation is available at `Read the Docs `_. +Documentation is available at `Read the Docs `_. Quickstart diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css index 611e1be..2daab60 100644 --- a/docs/source/_static/css/custom.css +++ b/docs/source/_static/css/custom.css @@ -1,7 +1,7 @@ -.py.class { - padding: 1.5em 0em 1.5em; +.content { + width: 55em; } -.py.data, .py.method, .py.property, .py.exception, .py.function { - padding: 0.5em 0em 0.5em; +.sidebar-drawer { + width: 15em; } diff --git a/docs/source/conf.py b/docs/source/conf.py index c764ea0..40f7d52 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,26 +10,22 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -import enum import sys from pathlib import Path -THIS_PATH = Path(__file__).parent -sys.path.insert(0, str(THIS_PATH.parent.parent)) - -import pjrpc.common.typedefs # noqa -import pjrpc.server.typedefs # noqa +import toml -# -- Project information ----------------------------------------------------- - -project = pjrpc.__title__ -author = pjrpc.__author__ -copyright = '2019, {}'.format(author) +THIS_PATH = Path(__file__).parent +ROOT_PATH = THIS_PATH.parent.parent +sys.path.insert(0, str(ROOT_PATH)) -# The full version, including alpha/beta/rc tags -release = pjrpc.__version__ -version = pjrpc.__version__ +PYPROJECT = toml.load(ROOT_PATH / 'pyproject.toml') +PROJECT_INFO = PYPROJECT['tool']['poetry'] +project = PROJECT_INFO['name'] +copyright = f"2023, {PROJECT_INFO['name']}" +author = PROJECT_INFO['authors'][0] +release = PROJECT_INFO['version'] # -- General configuration --------------------------------------------------- @@ -40,68 +36,37 @@ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', + 'sphinx.ext.autosectionlabel', + 'sphinx.ext.viewcode', + 'sphinx_copybutton', + 'sphinx_design', ] -html_theme_options = { - 'github_user': 'dapper91', - 'github_repo': 'pjrpc', - 'github_banner': True, -} - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = [] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -html_css_files = ['css/custom.css'] - -# The master toctree document. -master_doc = 'index' - intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), 'aiohttp': ('https://aiohttp.readthedocs.io/en/stable/', None), 'requests': ('https://requests.kennethreitz.org/en/master/', None), } -autodoc_mock_imports = ['attrs'] autodoc_typehints = 'description' autodoc_typehints_format = 'short' autodoc_member_order = 'bysource' autodoc_default_options = { 'show-inheritance': True, } -autodoc_type_aliases = { - type_name: f'{pjrpc.common.typedefs.__name__}.{type_name}' - for type_name in pjrpc.common.typedefs.__all__ -} | { - type_name: f'{pjrpc.server.typedefs.__name__}.{type_name}' - for type_name in pjrpc.server.typedefs.__all__ -} -def maybe_skip_member(app, what, name, obj, skip, options): - if isinstance(obj, enum.Enum): - return False +autosectionlabel_prefix_document = True - return None +html_theme_options = {} +html_title = PROJECT_INFO['name'] +templates_path = ['_templates'] +exclude_patterns = [] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -def setup(app): - app.connect('autodoc-skip-member', maybe_skip_member) +html_theme = 'furo' +html_static_path = ['_static'] +html_css_files = ['css/custom.css'] diff --git a/docs/source/index.rst b/docs/source/index.rst index 4e2f8db..0b9648d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,8 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to pjrpc's documentation! -================================= +Python JSON-RPC without boilerplate +=================================== .. image:: https://static.pepy.tech/personalized-badge/pjrpc?period=month&units=international_system&left_color=grey&right_color=orange&left_text=Downloads/month @@ -99,6 +99,12 @@ Development pjrpc/development +Links +----- + +- `Source code `_ + + Indices and tables ================== diff --git a/docs/source/pjrpc/api/client.rst b/docs/source/pjrpc/api/client.rst index 2833db5..bfc6828 100644 --- a/docs/source/pjrpc/api/client.rst +++ b/docs/source/pjrpc/api/client.rst @@ -3,10 +3,13 @@ Client ------ +Misc +~~~~ .. automodule:: pjrpc.client :members: + Backends ~~~~~~~~ diff --git a/docs/source/pjrpc/api/common.rst b/docs/source/pjrpc/api/common.rst index f613cad..392a418 100644 --- a/docs/source/pjrpc/api/common.rst +++ b/docs/source/pjrpc/api/common.rst @@ -3,6 +3,8 @@ Common ------ +Misc +~~~~ .. automodule:: pjrpc.common :members: diff --git a/docs/source/pjrpc/api/server.rst b/docs/source/pjrpc/api/server.rst index 0942f93..bd1d80e 100644 --- a/docs/source/pjrpc/api/server.rst +++ b/docs/source/pjrpc/api/server.rst @@ -4,9 +4,13 @@ Server ------ +Misc +~~~~ + .. automodule:: pjrpc.server :members: + Types ~~~~~ diff --git a/docs/source/pjrpc/client.rst b/docs/source/pjrpc/client.rst index 4556be5..ea9eeb1 100644 --- a/docs/source/pjrpc/client.rst +++ b/docs/source/pjrpc/client.rst @@ -181,5 +181,5 @@ Id generators -------------- The library request id generator can also be customized. There are four generator types implemented in the library -see :py:mod:`pjrpc.common.generators`. You can implement your own one and pass it to a client by `id_gen` +see :py:mod:`pjrpc.common.generators`. You can implement your own one and pass it to a client by ``id_gen`` parameter. diff --git a/docs/source/pjrpc/extending.rst b/docs/source/pjrpc/extending.rst index a54c250..e6b7244 100644 --- a/docs/source/pjrpc/extending.rst +++ b/docs/source/pjrpc/extending.rst @@ -8,9 +8,9 @@ an JSON-RPC server implementation based on :py:mod:`http.server` standard python .. code-block:: python - import uuid import http.server import socketserver + import uuid import pjrpc import pjrpc.server @@ -19,20 +19,21 @@ an JSON-RPC server implementation based on :py:mod:`http.server` standard python class JsonRpcHandler(http.server.BaseHTTPRequestHandler): def do_POST(self): content_type = self.headers.get('Content-Type') - if content_type not in pjrpc.common.JSONRPC_REQUEST_CONTENT_TYPES: - self.send_response(http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE) + if content_type not in pjrpc.common.REQUEST_CONTENT_TYPES: + self.send_error(http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE) return try: content_length = int(self.headers.get('Content-Length', -1)) request_text = self.rfile.read(content_length).decode() except UnicodeDecodeError: - self.send_response(http.HTTPStatus.BAD_REQUEST) + self.send_error(http.HTTPStatus.BAD_REQUEST) return response_text = self.server.dispatcher.dispatch(request_text, context=self) if response_text is None: - self.send_response(http.HTTPStatus.OK) + self.send_response_only(http.HTTPStatus.OK) + self.end_headers() else: self.send_response(http.HTTPStatus.OK) self.send_header("Content-type", pjrpc.common.DEFAULT_CONTENT_TYPE) diff --git a/docs/source/pjrpc/specification.rst b/docs/source/pjrpc/specification.rst index 8bd230d..197d1fc 100644 --- a/docs/source/pjrpc/specification.rst +++ b/docs/source/pjrpc/specification.rst @@ -1,7 +1,7 @@ .. _specification: -Specification: -============== +Specification +============= ``pjrpc`` has built-in `OpenAPI `_ and `OpenRPC `_ diff --git a/docs/source/pjrpc/testing.rst b/docs/source/pjrpc/testing.rst index 5bf19ab..30c5156 100644 --- a/docs/source/pjrpc/testing.rst +++ b/docs/source/pjrpc/testing.rst @@ -8,6 +8,15 @@ pytest ------ ``pjrpc`` implements pytest plugin that simplifies JSON-RPC requests mocking. +To install the plugin add the following line to your pytest configuration: + +.. code-block:: python + + pytest_plugins = ("pjrpc.client.integrations.pytest ", ) + +or export the environment variable ``PYTEST_PLUGINS=pjrpc.client.integrations.pytest``. +For more information `see `_. + Look at the following test example: .. code-block:: python diff --git a/pjrpc/common/generators.py b/pjrpc/common/generators.py index e98d3a7..95a17b1 100644 --- a/pjrpc/common/generators.py +++ b/pjrpc/common/generators.py @@ -12,6 +12,9 @@ def sequential(start: int = 1, step: int = 1) -> Generator[int, None, None]: """ Sequential id generator. Returns consecutive values starting from `start` with step `step`. + + :param start: starting number + :param step: step """ yield from it.count(start, step) @@ -20,6 +23,9 @@ def sequential(start: int = 1, step: int = 1) -> Generator[int, None, None]: def randint(a: int, b: int) -> Generator[int, None, None]: """ Random integer id generator. Returns random integers between `a` and `b`. + + :param a: from + :param b: to """ while True: @@ -29,6 +35,9 @@ def randint(a: int, b: int) -> Generator[int, None, None]: def random(length: int = 8, chars: str = string.digits + string.ascii_lowercase) -> Generator[str, None, None]: """ Random string id generator. Returns random strings of length `length` using alphabet `chars`. + + :param length: string length + :param chars: string characters """ while True: diff --git a/pyproject.toml b/pyproject.toml index 8f4c879..9c6b3c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ license = "Unlicense" readme = "README.rst" homepage = "https://github.com/dapper91/pjrpc" repository = "https://github.com/dapper91/pjrpc" -documentation = "https://pjrpc.readthedocs.io/en/latest/" +documentation = "https://pjrpc.readthedocs.io" keywords = [ 'json-rpc', 'rpc', 'jsonrpc-client', 'jsonrpc-server', 'requests', 'aiohttp', 'flask', 'httpx', 'aio-pika', 'kombu', @@ -50,7 +50,13 @@ pydantic = { version = "^1.7.0", optional = true } requests = { version = "^2.0", optional = true } starlette = { version = "^0.12.0", optional = true } werkzeug = { version = "~=2.0", optional = true} -sphinx = { version = "~=4.5", optional = true} + +furo = {version = "^2022.12.7", optional = true} +Sphinx = {version = "^5.3.0", optional = true} +sphinx-copybutton = {version = "^0.5.1", optional = true} +sphinx_design = {version = "^0.3.0", optional = true} +toml = {version = "^0.10.2", optional = true} + [tool.poetry.extras] aio-pika = ['aio-pika'] @@ -67,7 +73,10 @@ requests = ['requests'] starlette = ['starlette', 'aiofiles'] test = ['docstring-parser', 'flask', 'jsonschema', 'openapi-ui-bundles', 'pydantic', 'werkzeug'] werkzeug = ['werkzeug'] -docgen = ['sphinx', 'aiohttp', 'aio-pika', 'flask', 'jsonschema', 'pydantic', 'requests', 'kombu'] +docs = [ + 'sphinx', 'sphinx-copybutton', 'sphinx_design', 'furo', 'toml', + 'aiohttp', 'aio-pika', 'flask', 'jsonschema', 'pydantic', 'requests', 'kombu' +] [tool.poetry.dev-dependencies] aioresponses = "^0.7" From c5a5a24aa20f4f2899c13507d1d63f4293063246 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:22:30 +0500 Subject: [PATCH 10/14] python 3.11 support added. --- .github/workflows/test.yml | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2a99384..eb000a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.8', '3.9', '3.10'] + python-version: ['3.8', '3.9', '3.10', '3.11'] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/pyproject.toml b/pyproject.toml index 9c6b3c1..5d9d3d5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,15 +26,15 @@ classifiers = [ "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Application Frameworks", "Programming Language :: Python", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ] [tool.poetry.dependencies] -python = "^3.7" +python = "^3.8" aio-pika = { version = "^8.0", optional = true } aiofiles = { version = "^0.7", optional = true } aiohttp = { version = "^3.7", optional = true } From dccefa42e5e68808d499c9d05224f14ca97cd23f Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:31:43 +0500 Subject: [PATCH 11/14] test dependencies updated. --- pyproject.toml | 18 +++++++++--------- pytest.ini | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 pytest.ini diff --git a/pyproject.toml b/pyproject.toml index 5d9d3d5..bbae2b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,15 +79,15 @@ docs = [ ] [tool.poetry.dev-dependencies] -aioresponses = "^0.7" -asynctest = "^0.12" -codecov = "^2.0" -pytest = "^6.0" -pytest-aiohttp = "^0.3" -pytest-cov = "^2.0" -pytest-mock = "^1.0" -responses = "^0.14" -respx = "^0.19.2" +aioresponses = "^0.7.4" +asynctest = "^0.13.0" +codecov = "^2.1.13" +pytest = "^7.4.0" +pytest-aiohttp = "^1.0.4" +pytest-cov = "^4.1.0" +pytest-mock = "^3.11.1" +responses = "^0.23.3" +respx = "^0.20.2" mypy = "^1.4.1" pre-commit = "^2.19" diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..4088045 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +asyncio_mode=auto From e48b6cfd8cd88727a4a3646623e7f5498468e7b6 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 19:32:09 +0500 Subject: [PATCH 12/14] project dependencies updated. --- pyproject.toml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bbae2b6..3d64c45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,22 +34,22 @@ classifiers = [ [tool.poetry.dependencies] -python = "^3.8" -aio-pika = { version = "^8.0", optional = true } -aiofiles = { version = "^0.7", optional = true } -aiohttp = { version = "^3.7", optional = true } -django = { version = "^3.0", optional = true } -docstring-parser = { version = "^0.8", optional = true } +python = ">=3.8,<4.0" +aio-pika = { version = ">=8.0", optional = true } +aiofiles = { version = ">=0.7", optional = true } +aiohttp = { version = ">=3.7", optional = true } +django = { version = ">=3.0", optional = true } +docstring-parser = { version = ">=0.8", optional = true } flask = { version = ">=1.1.3", optional = true } -httpx = { version = "^0.23.0", optional = true } -jsonschema = { version = "^3.0", optional = true } -kombu = { version = "^5.1", optional = true } +httpx = { version = ">=0.23.0", optional = true } +jsonschema = {version = ">=3.0,<4.0", optional = true} +kombu = { version = ">=5.1", optional = true } markupsafe = { version = "==2.0.1", optional = true } -openapi-ui-bundles = { version = "^0.1", optional = true } -pydantic = { version = "^1.7.0", optional = true } -requests = { version = "^2.0", optional = true } -starlette = { version = "^0.12.0", optional = true } -werkzeug = { version = "~=2.0", optional = true} +openapi-ui-bundles = { version = ">=0.1", optional = true } +pydantic = {version = ">=1.7.0,<2.0", optional = true} +requests = { version = ">=2.0", optional = true } +starlette = { version = ">=0.25.0", optional = true } +werkzeug = { version = ">=2.0", optional = true} furo = {version = "^2022.12.7", optional = true} Sphinx = {version = "^5.3.0", optional = true} From f9ba1144e5c85d7664658d3210f639db1d749305 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 20:09:27 +0500 Subject: [PATCH 13/14] bump version 1.7.0. --- CHANGELOG.rst | 8 ++++++++ pjrpc/__about__.py | 4 ++-- pyproject.toml | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6046182..68c6f6b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ Changelog ========= +1.7.0 (2023-08-10) +------------------ + +- refactoring done +- dependencies updated +- python 3.11 support added + + 1.6.0 (2022-07-05) ------------------ diff --git a/pjrpc/__about__.py b/pjrpc/__about__.py index 2805763..3e20f1d 100644 --- a/pjrpc/__about__.py +++ b/pjrpc/__about__.py @@ -2,9 +2,9 @@ __description__ = 'Extensible JSON-RPC library' __url__ = 'https://github.com/dapper91/pjrpc' -__version__ = '1.6.0' +__version__ = '1.7.0' __author__ = 'Dmitry Pershin' -__email__ = 'dapper91@mail.ru' +__email__ = 'dapper1291@gmail.com' __license__ = 'Public Domain License' diff --git a/pyproject.toml b/pyproject.toml index 3d64c45..13a6ae5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pjrpc" -version = "1.6.0" +version = "1.7.0" description = "Extensible JSON-RPC library" authors = ["Dmitry Pershin "] license = "Unlicense" From a79c33a75eb4f4f62e78f640aed22f72023bb247 Mon Sep 17 00:00:00 2001 From: Dmitry Pershin Date: Thu, 10 Aug 2023 20:12:52 +0500 Subject: [PATCH 14/14] build budge updated. --- docs/source/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 0b9648d..79b2d4c 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -10,8 +10,8 @@ Python JSON-RPC without boilerplate .. image:: https://static.pepy.tech/personalized-badge/pjrpc?period=month&units=international_system&left_color=grey&right_color=orange&left_text=Downloads/month :target: https://pepy.tech/project/pjrpc :alt: Downloads/month -.. image:: https://travis-ci.org/dapper91/pjrpc.svg?branch=master - :target: https://travis-ci.org/dapper91/pjrpc +.. image:: https://github.com/dapper91/pjrpc/actions/workflows/test.yml/badge.svg?branch=master + :target: https://github.com/dapper91/pjrpc/actions/workflows/test.yml :alt: Build status .. image:: https://img.shields.io/pypi/l/pjrpc.svg :target: https://pypi.org/project/pjrpc