From 78920048a752ba075cfa8a6a2306229d2875d8a2 Mon Sep 17 00:00:00 2001 From: zerlok Date: Thu, 21 Nov 2024 20:41:05 +0100 Subject: [PATCH 1/9] refactor visitor, remove return value --- src/pyprotostuben/codegen/module_ast.py | 5 +- src/pyprotostuben/codegen/mypy/generator.py | 95 +++---- src/pyprotostuben/protobuf/visitor/abc.py | 20 +- .../protobuf/visitor/decorator.py | 237 +++++++----------- src/pyprotostuben/protobuf/visitor/walker.py | 205 +++++---------- src/pyprotostuben/protoc.py | 6 +- 6 files changed, 204 insertions(+), 364 deletions(-) diff --git a/src/pyprotostuben/codegen/module_ast.py b/src/pyprotostuben/codegen/module_ast.py index c3a93dd..f06a57f 100644 --- a/src/pyprotostuben/codegen/module_ast.py +++ b/src/pyprotostuben/codegen/module_ast.py @@ -14,7 +14,7 @@ @dataclass(frozen=True) class ModuleASTContext: file: ProtoFile - modules: t.Mapping[Path, ast.Module] + modules: t.MutableMapping[Path, ast.Module] T = t.TypeVar("T", bound=ModuleASTContext) @@ -29,7 +29,8 @@ def run(self, file: ProtoFile) -> t.Sequence[GeneratedItem]: log = self._log.bind_details(file_name=file.name) log.debug("file received") - context = self.__walker.walk(self.__context_factory(file), file.descriptor) + context = self.__context_factory(file) + self.__walker.walk(context, file.descriptor) log.debug("proto visited", context=context) return list(self.__gen_modules(context, log)) diff --git a/src/pyprotostuben/codegen/mypy/generator.py b/src/pyprotostuben/codegen/mypy/generator.py index e595622..36e5a22 100644 --- a/src/pyprotostuben/codegen/mypy/generator.py +++ b/src/pyprotostuben/codegen/mypy/generator.py @@ -1,5 +1,5 @@ import typing as t -from dataclasses import dataclass, replace +from dataclasses import dataclass from google.protobuf.descriptor_pb2 import SourceCodeInfo @@ -41,37 +41,33 @@ def __init__( self.__message_context_factory = message_context_factory self.__grpc_context_factory = grpc_context_factory - def enter_file_descriptor_proto(self, context: FileDescriptorContext[MypyStubContext]) -> MypyStubContext: + def enter_file_descriptor_proto(self, context: FileDescriptorContext[MypyStubContext]) -> None: context.meta.messages.put(self.__message_context_factory(context.file)) context.meta.grpcs.put(self.__grpc_context_factory(context.file)) - return context.meta - - def leave_file_descriptor_proto(self, context: FileDescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_file_descriptor_proto(self, context: FileDescriptorContext[MypyStubContext]) -> None: message = context.meta.messages.pop() grpc = context.meta.grpcs.pop() - modules = { - message.module.stub_file: message.builder.build_protobuf_message_module( - deps=message.external_modules, - body=message.nested, - ), - grpc.module.stub_file: grpc.builder.build_grpc_module( - deps=grpc.external_modules, - body=grpc.nested, - ), - } - - return replace(context.meta, modules={**context.meta.modules, **modules}) + context.meta.modules.update( + { + message.module.stub_file: message.builder.build_protobuf_message_module( + deps=message.external_modules, + body=message.nested, + ), + grpc.module.stub_file: grpc.builder.build_grpc_module( + deps=grpc.external_modules, + body=grpc.nested, + ), + } + ) - def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[MypyStubContext]) -> MypyStubContext: + def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[MypyStubContext]) -> None: parent = context.meta.messages.get_last() context.meta.messages.put(parent.sub()) - return context.meta - - def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[MypyStubContext]) -> None: message = context.meta.messages.pop() parent = context.meta.messages.get_last() builder = message.builder @@ -84,17 +80,10 @@ def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[MypyStubCon ) ) - return context.meta - - def enter_enum_value_descriptor_proto( - self, - context: EnumValueDescriptorContext[MypyStubContext], - ) -> MypyStubContext: - return context.meta + def enter_enum_value_descriptor_proto(self, _: EnumValueDescriptorContext[MypyStubContext]) -> None: + pass - def leave_enum_value_descriptor_proto( - self, context: EnumValueDescriptorContext[MypyStubContext] - ) -> MypyStubContext: + def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[MypyStubContext]) -> None: parent = context.meta.messages.get_last() builder = parent.builder @@ -106,20 +95,16 @@ def leave_enum_value_descriptor_proto( ) ) - return context.meta - - def enter_descriptor_proto(self, context: DescriptorContext[MypyStubContext]) -> MypyStubContext: + def enter_descriptor_proto(self, context: DescriptorContext[MypyStubContext]) -> None: parent = context.meta.messages.get_last() context.meta.messages.put(parent.sub()) - return context.meta - - def leave_descriptor_proto(self, context: DescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_descriptor_proto(self, context: DescriptorContext[MypyStubContext]) -> None: message = context.meta.messages.pop() if context.item.options.map_entry: - return context.meta + return parent = context.meta.messages.get_last() builder = message.builder @@ -133,21 +118,17 @@ def leave_descriptor_proto(self, context: DescriptorContext[MypyStubContext]) -> ), ) - return context.meta + def enter_oneof_descriptor_proto(self, _: OneofDescriptorContext[MypyStubContext]) -> None: + pass - def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[MypyStubContext]) -> MypyStubContext: - return context.meta - - def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[MypyStubContext]) -> None: info = context.meta.messages.get_last() info.oneof_groups.append(context.item.name) - return context.meta - - def enter_field_descriptor_proto(self, context: FieldDescriptorContext[MypyStubContext]) -> MypyStubContext: - return context.meta + def enter_field_descriptor_proto(self, _: FieldDescriptorContext[MypyStubContext]) -> None: + pass - def leave_field_descriptor_proto(self, context: FieldDescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_field_descriptor_proto(self, context: FieldDescriptorContext[MypyStubContext]) -> None: is_optional = context.item.proto3_optional message = context.meta.messages.get_last() builder = message.builder @@ -172,16 +153,12 @@ def leave_field_descriptor_proto(self, context: FieldDescriptorContext[MypyStubC ), ) - return context.meta - - def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[MypyStubContext]) -> MypyStubContext: + def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[MypyStubContext]) -> None: parent = context.meta.grpcs.get_last() context.meta.grpcs.put(parent.sub()) - return context.meta - - def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[MypyStubContext]) -> None: grpc = context.meta.grpcs.pop() parent = context.meta.grpcs.get_last() builder = grpc.builder @@ -190,12 +167,10 @@ def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[MypyS parent.nested.extend(builder.build_grpc_servicer_defs(f"{context.item.name}Servicer", doc, grpc.methods)) parent.nested.extend(builder.build_grpc_stub_defs(f"{context.item.name}Stub", doc, grpc.methods)) - return context.meta + def enter_method_descriptor_proto(self, context: MethodDescriptorContext[MypyStubContext]) -> None: + pass - def enter_method_descriptor_proto(self, context: MethodDescriptorContext[MypyStubContext]) -> MypyStubContext: - return context.meta - - def leave_method_descriptor_proto(self, context: MethodDescriptorContext[MypyStubContext]) -> MypyStubContext: + def leave_method_descriptor_proto(self, context: MethodDescriptorContext[MypyStubContext]) -> None: grpc = context.meta.grpcs.get_last() builder = grpc.builder @@ -214,8 +189,6 @@ def leave_method_descriptor_proto(self, context: MethodDescriptorContext[MypyStu ), ) - return context.meta - def __get_doc(self, location: t.Optional[SourceCodeInfo.Location]) -> t.Optional[str]: if location is None: return None diff --git a/src/pyprotostuben/protobuf/visitor/abc.py b/src/pyprotostuben/protobuf/visitor/abc.py index fa30215..bdee62d 100644 --- a/src/pyprotostuben/protobuf/visitor/abc.py +++ b/src/pyprotostuben/protobuf/visitor/abc.py @@ -12,38 +12,38 @@ ServiceDescriptorContext, ) -T = t.TypeVar("T") +T_contra = t.TypeVar("T_contra", contravariant=True) -class ProtoVisitor(t.Generic[T], metaclass=abc.ABCMeta): +class ProtoVisitor(t.Generic[T_contra], metaclass=abc.ABCMeta): @abc.abstractmethod - def visit_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: + def visit_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: + def visit_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: + def visit_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_descriptor_proto(self, context: DescriptorContext[T]) -> T: + def visit_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: + def visit_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: + def visit_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: + def visit_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def visit_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: + def visit_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: raise NotImplementedError diff --git a/src/pyprotostuben/protobuf/visitor/decorator.py b/src/pyprotostuben/protobuf/visitor/decorator.py index 90af367..9c897d4 100644 --- a/src/pyprotostuben/protobuf/visitor/decorator.py +++ b/src/pyprotostuben/protobuf/visitor/decorator.py @@ -1,6 +1,5 @@ import abc import typing as t -from dataclasses import replace from pyprotostuben.protobuf.visitor.abc import ProtoVisitor from pyprotostuben.protobuf.visitor.model import ( @@ -14,256 +13,192 @@ ServiceDescriptorContext, ) -T = t.TypeVar("T") +T_contra = t.TypeVar("T_contra", contravariant=True) -class ProtoVisitorDecorator(t.Generic[T], metaclass=abc.ABCMeta): +class ProtoVisitorDecorator(t.Generic[T_contra], metaclass=abc.ABCMeta): @abc.abstractmethod - def enter_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: + def enter_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: + def leave_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: + def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: + def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: + def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: + def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_descriptor_proto(self, context: DescriptorContext[T]) -> T: + def enter_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_descriptor_proto(self, context: DescriptorContext[T]) -> T: + def leave_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: + def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: + def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: + def enter_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: + def leave_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: + def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: + def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def enter_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: + def enter_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: raise NotImplementedError @abc.abstractmethod - def leave_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: + def leave_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: raise NotImplementedError -class EnterProtoVisitorDecorator(ProtoVisitorDecorator[T]): - def __init__(self, *nested: ProtoVisitor[T]) -> None: +class EnterProtoVisitorDecorator(ProtoVisitorDecorator[T_contra]): + def __init__(self, *nested: ProtoVisitor[T_contra]) -> None: self.__nested = nested - def enter_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: - meta = context.meta - + def enter_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_file_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_file_descriptor_proto(context) - def leave_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: - return context.meta - - def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: - meta = context.meta + def leave_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: + pass + def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_enum_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_enum_descriptor_proto(context) - def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: - return context.meta - - def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: - meta = context.meta + def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: + pass + def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_enum_value_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_enum_value_descriptor_proto(context) - def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: - return context.meta - - def enter_descriptor_proto(self, context: DescriptorContext[T]) -> T: - meta = context.meta + def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: + pass + def enter_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_descriptor_proto(context) - def leave_descriptor_proto(self, context: DescriptorContext[T]) -> T: - return context.meta - - def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: - meta = context.meta + def leave_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: + pass + def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_oneof_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_oneof_descriptor_proto(context) - def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: - return context.meta - - def enter_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: - meta = context.meta + def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: + pass + def enter_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_field_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_field_descriptor_proto(context) - def leave_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: - return context.meta - - def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: - meta = context.meta + def leave_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: + pass + def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_service_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_service_descriptor_proto(context) - def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: - return context.meta - - def enter_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: - meta = context.meta + def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: + pass + def enter_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_method_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_method_descriptor_proto(context) - def leave_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: - return context.meta + def leave_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: + pass -class LeaveProtoVisitorDecorator(ProtoVisitorDecorator[T]): - def __init__(self, *nested: ProtoVisitor[T]) -> None: +class LeaveProtoVisitorDecorator(ProtoVisitorDecorator[T_contra]): + def __init__(self, *nested: ProtoVisitor[T_contra]) -> None: self.__nested = nested - def enter_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: - return context.meta - - def leave_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: - meta = context.meta + def enter_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: + pass + def leave_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_file_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_file_descriptor_proto(context) - def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: - return context.meta - - def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: - meta = context.meta + def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: + pass + def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_enum_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_enum_descriptor_proto(context) - def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: - return context.meta - - def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: - meta = context.meta + def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: + pass + def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_enum_value_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_enum_value_descriptor_proto(context) - def enter_descriptor_proto(self, context: DescriptorContext[T]) -> T: - return context.meta - - def leave_descriptor_proto(self, context: DescriptorContext[T]) -> T: - meta = context.meta + def enter_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: + pass + def leave_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_descriptor_proto(context) - def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: - return context.meta - - def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: - meta = context.meta + def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: + pass + def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_oneof_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_oneof_descriptor_proto(context) - def enter_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: - return context.meta - - def leave_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: - meta = context.meta + def enter_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: + pass + def leave_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_field_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_field_descriptor_proto(context) - def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: - return context.meta - - def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: - meta = context.meta + def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: + pass + def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_service_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_service_descriptor_proto(context) - def enter_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: - return context.meta - - def leave_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: - meta = context.meta + def enter_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: + pass + def leave_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: for nested in self.__nested: - meta = nested.visit_method_descriptor_proto(replace(context, meta=meta)) - - return meta + nested.visit_method_descriptor_proto(context) diff --git a/src/pyprotostuben/protobuf/visitor/walker.py b/src/pyprotostuben/protobuf/visitor/walker.py index 4257080..14f226d 100644 --- a/src/pyprotostuben/protobuf/visitor/walker.py +++ b/src/pyprotostuben/protobuf/visitor/walker.py @@ -1,5 +1,4 @@ import typing as t -from dataclasses import replace from google.protobuf.descriptor_pb2 import ( DescriptorProto, @@ -23,175 +22,143 @@ ServiceDescriptorContext, ) -T = t.TypeVar("T") +T_contra = t.TypeVar("T_contra", contravariant=True) -class Walker(ProtoVisitor[T], LoggerMixin): - def __init__(self, *nested: ProtoVisitorDecorator[T]) -> None: +class Walker(ProtoVisitor[T_contra], LoggerMixin): + def __init__(self, *nested: ProtoVisitorDecorator[T_contra]) -> None: self.__nested = nested - def visit_file_descriptor_proto(self, context: FileDescriptorContext[T]) -> T: + def visit_file_descriptor_proto(self, context: FileDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_file_descriptor_proto(replace(context, meta=meta)) + nested.enter_file_descriptor_proto(context) - meta = self.__walk_enums(replace(context, meta=meta)) - meta = self.__walk_message_types(replace(context, meta=meta)) - meta = self.__walk_services(replace(context, meta=meta)) - meta = self.__walk_extensions(replace(context, meta=meta)) + self.__walk_enums(context) + self.__walk_message_types(context) + self.__walk_services(context) + self.__walk_extensions(context) for nested in reversed(self.__nested): - meta = nested.leave_file_descriptor_proto(replace(context, meta=meta)) + nested.leave_file_descriptor_proto(context) log.info("visited") - return meta - - def visit_enum_descriptor_proto(self, context: EnumDescriptorContext[T]) -> T: + def visit_enum_descriptor_proto(self, context: EnumDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_enum_descriptor_proto(replace(context, meta=meta)) + nested.enter_enum_descriptor_proto(context) - meta = self.__walk_enum_values(replace(context, meta=meta)) + self.__walk_enum_values(context) for nested in reversed(self.__nested): - meta = nested.leave_enum_descriptor_proto(replace(context, meta=meta)) + nested.leave_enum_descriptor_proto(context) log.info("visited") - return meta - - def visit_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T]) -> T: + def visit_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_enum_value_descriptor_proto(replace(context, meta=meta)) + nested.enter_enum_value_descriptor_proto(context) for nested in reversed(self.__nested): - meta = nested.leave_enum_value_descriptor_proto(replace(context, meta=meta)) + nested.leave_enum_value_descriptor_proto(context) log.info("visited") - return meta - - def visit_descriptor_proto(self, context: DescriptorContext[T]) -> T: + def visit_descriptor_proto(self, context: DescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_descriptor_proto(replace(context, meta=meta)) + nested.enter_descriptor_proto(context) - meta = self.__walk_enums(replace(context, meta=meta)) - meta = self.__walk_nested_types(replace(context, meta=meta)) - meta = self.__walk_oneofs(replace(context, meta=meta)) - meta = self.__walk_fields(replace(context, meta=meta)) - meta = self.__walk_extensions(replace(context, meta=meta)) + self.__walk_enums(context) + self.__walk_nested_types(context) + self.__walk_oneofs(context) + self.__walk_fields(context) + self.__walk_extensions(context) for nested in reversed(self.__nested): - meta = nested.leave_descriptor_proto(replace(context, meta=meta)) + nested.leave_descriptor_proto(context) log.info("visited") - return meta - - def visit_oneof_descriptor_proto(self, context: OneofDescriptorContext[T]) -> T: + def visit_oneof_descriptor_proto(self, context: OneofDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_oneof_descriptor_proto(replace(context, meta=meta)) + nested.enter_oneof_descriptor_proto(context) for nested in reversed(self.__nested): - meta = nested.leave_oneof_descriptor_proto(replace(context, meta=meta)) + nested.leave_oneof_descriptor_proto(context) log.info("visited") - return meta - - def visit_field_descriptor_proto(self, context: FieldDescriptorContext[T]) -> T: + def visit_field_descriptor_proto(self, context: FieldDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_field_descriptor_proto(replace(context, meta=meta)) + nested.enter_field_descriptor_proto(context) for nested in reversed(self.__nested): - meta = nested.leave_field_descriptor_proto(replace(context, meta=meta)) + nested.leave_field_descriptor_proto(context) log.info("visited") - return meta - - def visit_service_descriptor_proto(self, context: ServiceDescriptorContext[T]) -> T: + def visit_service_descriptor_proto(self, context: ServiceDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_service_descriptor_proto(replace(context, meta=meta)) + nested.enter_service_descriptor_proto(context) - meta = self.__walk_methods(replace(context, meta=meta)) + self.__walk_methods(context) for nested in reversed(self.__nested): - meta = nested.leave_service_descriptor_proto(replace(context, meta=meta)) + nested.leave_service_descriptor_proto(context) log.info("visited") - return meta - - def visit_method_descriptor_proto(self, context: MethodDescriptorContext[T]) -> T: + def visit_method_descriptor_proto(self, context: MethodDescriptorContext[T_contra]) -> None: proto = context.item log = self._log.bind_details(proto_name=proto.name) log.debug("entered") - meta = context.meta - for nested in self.__nested: - meta = nested.enter_method_descriptor_proto(replace(context, meta=meta)) + nested.enter_method_descriptor_proto(context) for nested in reversed(self.__nested): - meta = nested.leave_method_descriptor_proto(replace(context, meta=meta)) + nested.leave_method_descriptor_proto(context) log.info("visited") - return meta - - def walk(self, meta: T, *files: FileDescriptorProto) -> T: + def walk(self, meta: T_contra, *files: FileDescriptorProto) -> None: for file in files: - meta = self.visit_file_descriptor_proto( + self.visit_file_descriptor_proto( FileDescriptorContext( meta=meta, item=file, @@ -199,139 +166,101 @@ def walk(self, meta: T, *files: FileDescriptorProto) -> T: ) ) - return meta - - def __walk_enums(self, context: BaseContext[T, FileDescriptorProto | DescriptorProto]) -> T: - meta = context.meta - + def __walk_enums(self, context: BaseContext[T_contra, FileDescriptorProto | DescriptorProto]) -> None: for i, enum_type in enumerate(context.item.enum_type): - meta = self.visit_enum_descriptor_proto( + self.visit_enum_descriptor_proto( EnumDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=enum_type, path=(*context.path, context.item.ENUM_TYPE_FIELD_NUMBER, i), ) ) - return meta - - def __walk_enum_values(self, context: BaseContext[T, EnumDescriptorProto]) -> T: - meta = context.meta - + def __walk_enum_values(self, context: BaseContext[T_contra, EnumDescriptorProto]) -> None: for i, value in enumerate(context.item.value): - meta = self.visit_enum_value_descriptor_proto( + self.visit_enum_value_descriptor_proto( EnumValueDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=value, path=(*context.path, context.item.VALUE_FIELD_NUMBER, i), ) ) - return meta - - def __walk_message_types(self, context: BaseContext[T, FileDescriptorProto]) -> T: - meta = context.meta - + def __walk_message_types(self, context: BaseContext[T_contra, FileDescriptorProto]) -> None: for i, message_type in enumerate(context.item.message_type): - meta = self.visit_descriptor_proto( + self.visit_descriptor_proto( DescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=message_type, path=(*context.path, context.item.MESSAGE_TYPE_FIELD_NUMBER, i), ) ) - return meta - - def __walk_nested_types(self, context: BaseContext[T, DescriptorProto]) -> T: - meta = context.meta - + def __walk_nested_types(self, context: BaseContext[T_contra, DescriptorProto]) -> None: for i, nested_type in enumerate(context.item.nested_type): - meta = self.visit_descriptor_proto( + self.visit_descriptor_proto( DescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=nested_type, path=(*context.path, context.item.NESTED_TYPE_FIELD_NUMBER, i), ) ) - return meta - - def __walk_oneofs(self, context: BaseContext[T, DescriptorProto]) -> T: - meta = context.meta - + def __walk_oneofs(self, context: BaseContext[T_contra, DescriptorProto]) -> None: for i, oneof in enumerate(context.item.oneof_decl): - meta = self.visit_oneof_descriptor_proto( + self.visit_oneof_descriptor_proto( OneofDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=oneof, path=(*context.path, context.item.ONEOF_DECL_FIELD_NUMBER, i), ) ) - return meta - - def __walk_fields(self, context: BaseContext[T, DescriptorProto]) -> T: - meta = context.meta - + def __walk_fields(self, context: BaseContext[T_contra, DescriptorProto]) -> None: for i, field in enumerate(context.item.field): - meta = self.visit_field_descriptor_proto( + self.visit_field_descriptor_proto( FieldDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=field, path=(*context.path, context.item.FIELD_FIELD_NUMBER, i), ) ) - return meta - - def __walk_services(self, context: BaseContext[T, FileDescriptorProto]) -> T: - meta = context.meta - + def __walk_services(self, context: BaseContext[T_contra, FileDescriptorProto]) -> None: for i, service in enumerate(context.item.service): - meta = self.visit_service_descriptor_proto( + self.visit_service_descriptor_proto( ServiceDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=service, path=(*context.path, context.item.SERVICE_FIELD_NUMBER, i), ) ) - return meta - - def __walk_methods(self, context: BaseContext[T, ServiceDescriptorProto]) -> T: - meta = context.meta - + def __walk_methods(self, context: BaseContext[T_contra, ServiceDescriptorProto]) -> None: for i, method in enumerate(context.item.method): - meta = self.visit_method_descriptor_proto( + self.visit_method_descriptor_proto( MethodDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=method, path=(*context.path, context.item.METHOD_FIELD_NUMBER, i), ) ) - return meta - - def __walk_extensions(self, context: BaseContext[T, FileDescriptorProto | DescriptorProto]) -> T: - meta = context.meta - + def __walk_extensions(self, context: BaseContext[T_contra, FileDescriptorProto | DescriptorProto]) -> None: for i, ext in enumerate(context.item.extension): - meta = self.visit_field_descriptor_proto( + self.visit_field_descriptor_proto( FieldDescriptorContext( - meta=meta, + meta=context.meta, parent_context=context, item=ext, path=(*context.path, context.item.EXTENSION_FIELD_NUMBER, i), ) ) - - return meta diff --git a/src/pyprotostuben/protoc.py b/src/pyprotostuben/protoc.py index 7534234..dc7a944 100644 --- a/src/pyprotostuben/protoc.py +++ b/src/pyprotostuben/protoc.py @@ -1,14 +1,16 @@ -from pyprotostuben.codegen.echo import RequestEchoProtocPlugin -from pyprotostuben.codegen.mypy.plugin import MypyStubProtocPlugin from pyprotostuben.codegen.run import run_codegen from pyprotostuben.logging import Logger def gen_mypy_stub() -> None: + from pyprotostuben.codegen.mypy.plugin import MypyStubProtocPlugin + Logger.configure() run_codegen(MypyStubProtocPlugin()) def echo() -> None: + from pyprotostuben.codegen.echo import RequestEchoProtocPlugin + Logger.configure() run_codegen(RequestEchoProtocPlugin()) From f0f5e987b21c0fdc6e1f11d2411f35fb828b57ff Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 00:53:07 +0100 Subject: [PATCH 2/9] add codegen plugin for BrokRPC --- README.md | 297 +++++++++++--- poetry.lock | 379 +++++++++++++++++- pyproject.toml | 6 +- src/pyprotostuben/codegen/brokrpc/__init__.py | 0 .../codegen/brokrpc/generator.py | 354 ++++++++++++++++ src/pyprotostuben/codegen/brokrpc/plugin.py | 83 ++++ src/pyprotostuben/codegen/module_ast.py | 2 +- src/pyprotostuben/codegen/mypy/generator.py | 2 +- src/pyprotostuben/protobuf/visitor/model.py | 16 + src/pyprotostuben/protoc.py | 7 + src/pyprotostuben/python/ast_builder.py | 120 ++++-- src/pyprotostuben/string_case.py | 12 + .../cases/case_000_greeting/case.py | 10 +- .../expected_gen/greeting_brokrpc.py | 32 ++ 14 files changed, 1227 insertions(+), 93 deletions(-) create mode 100644 src/pyprotostuben/codegen/brokrpc/__init__.py create mode 100644 src/pyprotostuben/codegen/brokrpc/generator.py create mode 100644 src/pyprotostuben/codegen/brokrpc/plugin.py create mode 100644 src/pyprotostuben/string_case.py create mode 100644 tests/integration/cases/case_000_greeting/expected_gen/greeting_brokrpc.py diff --git a/README.md b/README.md index 280b17f..739f249 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,19 @@ [![Downloads](https://img.shields.io/pypi/dm/pyprotostuben.svg)](https://pypistats.org/packages/pyprotostuben) [![GitHub stars](https://img.shields.io/github/stars/zerlok/pyprotostuben)](https://github.com/zerlok/pyprotostuben/stargazers) -Generate Python MyPy stub modules from protobuf files. +Generate Python modules from protobuf files. ## usage -install into dev dependencies group +[pypi package](https://pypi.python.org/pypi/pyprotostuben) + +install with your favorite python package manager ```bash -poetry add --group dev pyprotostuben +pip install pyprotostuben ``` -### protoc-gen-pyprotostuben +### protoc-gen-mypy-stub a protoc plugin that generates MyPy stubs @@ -37,16 +39,18 @@ a protoc plugin that generates MyPy stubs ## examples -#### requirements +requirements: -* protoc * [buf CLI](https://buf.build/product/cli) +* [protoc](https://grpc.io/docs/protoc-installation/) + +### mypy stubs -#### project structure +the following project structure with protobuf file in `proto3` syntax & buf `v1beta1` condigs: -* / - * src/ - * greeting.proto +* `/` + * `src/` + * `greeting.proto` ```protobuf syntax = "proto3"; @@ -68,14 +72,14 @@ a protoc plugin that generates MyPy stubs rpc Greet(GreetRequest) returns (GreetResponse) {} } ``` - * buf.yaml + * `buf.yaml` ```yaml version: v1beta1 build: roots: - src ``` - * buf.gen.yaml + * `buf.gen.yaml` ```yaml version: v1 managed: @@ -86,72 +90,241 @@ a protoc plugin that generates MyPy stubs strategy: all ``` -#### run codegen +run codegen ```bash buf generate ``` -#### output +the output: + +* `src/greeting_pb2.pyi` + ```python + import builtins + import google.protobuf.message + import typing + + class GreetRequest(google.protobuf.message.Message): + """RPC request for greeting""" + + def __init__(self, *, name: builtins.str) -> None:... + + @builtins.property + def name(self) -> builtins.str:... + + def HasField(self, field_name: typing.NoReturn) -> typing.NoReturn:... + + def WhichOneof(self, oneof_group: typing.NoReturn) -> typing.NoReturn:... + + class GreetResponse(google.protobuf.message.Message): + """RPC response for greeting""" + + def __init__(self, *, text: builtins.str) -> None:... + + @builtins.property + def text(self) -> builtins.str:... + + def HasField(self, field_name: typing.NoReturn) -> typing.NoReturn:... + + def WhichOneof(self, oneof_group: typing.NoReturn) -> typing.NoReturn:... + ``` +* `src/greeting_pb2_grpc.pyi` + ```python + import abc + import builtins + import greeting_pb2 + import grpc + import grpc.aio + import typing + + class GreeterServicer(metaclass=abc.ABCMeta): + """RPC service that provides greet functionality""" + + @abc.abstractmethod + async def Greet(self, request: greeting_pb2.GreetRequest, context: grpc.aio.ServicerContext[greeting_pb2.GreetRequest, greeting_pb2.GreetResponse]) -> greeting_pb2.GreetResponse: + """RPC method for greeting""" + ... + + def add_GreeterServicer_to_server(servicer: GreeterServicer, server: grpc.aio.Server) -> None:... + + class GreeterStub: + """RPC service that provides greet functionality""" + + def __init__(self, channel: grpc.aio.Channel) -> None:... + + def Greet(self, request: greeting_pb2.GreetRequest, *, timeout: typing.Optional[builtins.float]=None, metadata: typing.Optional[grpc.aio.MetadataType]=None, credentials: typing.Optional[grpc.CallCredentials]=None, wait_for_ready: typing.Optional[builtins.bool]=None, compression: typing.Optional[grpc.Compression]=None) -> grpc.aio.UnaryUnaryCall[greeting_pb2.GreetRequest, greeting_pb2.GreetResponse]: + """RPC method for greeting""" + ... + ``` + +### BrokRPC + +requirements: + +* [BrokRPC](https://github.com/zerlok/BrokRPC) -- to run RPC server & client code. Installed with pip `pip install BrokRPC[aiormq]`. + +create files: + +* `buf.yaml` + ```yaml + version: v2 + modules: + - path: src + lint: + use: + - DEFAULT + breaking: + use: + - FILE + ``` +* `buf.gen.yaml` + ```yaml + version: v2 + managed: + enabled: true + plugins: + # generates python protobuf message modules (the builtin protoc python codegen) + - protoc_builtin: python + out: out + # generates python mypy stubs for protobuf messages (stub generator from pyprotostuben) + - protoc_builtin: mypy-stub + out: out + # generates brokrpc files with server interface and client factory (also from pyprotostuben) + - protoc_builtin: brokrpc + out: out + strategy: all + ``` +* `src/greeting.proto` + ```protobuf + syntax = "proto3"; + + package greeting; + + // the greet request + message GreetRequest { + string name = 1; + } + + // the greet response + message GreetResponse { + string text = 1; + } + + // the greeter service + service Greeter { + // the greet method + rpc Greet(GreetRequest) returns (GreetResponse) {} + } + ``` + +then run codegen + +```shell +buf generate +``` -##### src/greeting_pb2.pyi +output: + +* `out/greeting_pb2.py` -- generated protobuf messages +* `out/greeting_pb2.pyi` -- generated mypy stubs for messages +* `out/greeting_brokrpc.py` + ```python + """Source: greeting.proto""" + import abc + import brokrpc.rpc.abc + import brokrpc.rpc.client + import brokrpc.rpc.model + import brokrpc.rpc.server + import brokrpc.serializer.protobuf + import contextlib + import greeting_pb2 + import typing + + class GreeterService(metaclass=abc.ABCMeta): + """the greeter service""" + + @abc.abstractmethod + async def greet(self, request: brokrpc.rpc.model.Request[greeting_pb2.GreetRequest]) -> greeting_pb2.GreetResponse: + """the greet method""" + raise NotImplementedError + + def add_greeter_service_to_server(service: GreeterService, server: brokrpc.rpc.server.Server) -> None: + server.register_unary_unary_handler(func=service.greet, routing_key='/greeting/Greeter/greet', serializer=brokrpc.serializer.protobuf.RPCProtobufSerializer(greeting_pb2.GreetRequest, greeting_pb2.GreetResponse)) + + class GreeterClient: + """the greeter service""" + + def __init__(self, greet: brokrpc.rpc.abc.Caller[greeting_pb2.GreetRequest, greeting_pb2.GreetResponse]) -> None: + self.__greet = greet + + async def greet(self, request: greeting_pb2.GreetRequest) -> brokrpc.rpc.model.Response[greeting_pb2.GreetResponse]: + """the greet method""" + return await self.__greet.invoke(request) + + @contextlib.asynccontextmanager + async def create_client(client: brokrpc.rpc.client.Client) -> typing.AsyncIterator[GreeterClient]: + async with client.unary_unary_caller(routing_key='/greeting/Greeter/greet', serializer=brokrpc.serializer.protobuf.RPCProtobufSerializer(greeting_pb2.GreetRequest, greeting_pb2.GreetResponse)) as greet: + yield GreeterClient(greet=greet) + ``` + +now on the server side you can implement the `GreeterService`, pass it to `add_greeter_service_to_server` and run the +**RPC server**. ```python -import builtins -import google.protobuf.message -import typing - -class GreetRequest(google.protobuf.message.Message): - """RPC request for greeting""" - - def __init__(self, *, name: builtins.str) -> None:... - - @builtins.property - def name(self) -> builtins.str:... +import asyncio - def HasField(self, field_name: typing.NoReturn) -> typing.NoReturn:... +from brokrpc.broker import Broker +from brokrpc.options import ExchangeOptions +from brokrpc.rpc.model import Request +from brokrpc.rpc.server import Server +from greeting_pb2 import GreetRequest, GreetResponse +from greeting_brokrpc import GreeterService, add_greeter_service_to_server - def WhichOneof(self, oneof_group: typing.NoReturn) -> typing.NoReturn:... -class GreetResponse(google.protobuf.message.Message): - """RPC response for greeting""" +class MyService(GreeterService): + async def greet(self, request: Request[GreetRequest]) -> GreetResponse: + return GreetResponse(text=f"hello, {request.body.name}") - def __init__(self, *, text: builtins.str) -> None:... - @builtins.property - def text(self) -> builtins.str:... +async def main() -> None: + broker = Broker("amqp://guest:guest@localhost:5672/", default_exchange=ExchangeOptions(name="test-greet-codegen")) + + server = Server(broker) + add_greeter_service_to_server(MyService(), server) + + await server.run_until_terminated() - def HasField(self, field_name: typing.NoReturn) -> typing.NoReturn:... - - def WhichOneof(self, oneof_group: typing.NoReturn) -> typing.NoReturn:... + +if __name__ == "__main__": + asyncio.run(main()) ``` -##### src/greeting_pb2_grpc.pyi +on the client side you just have to get the client from `create_client` using **RPC client** and you ready to send +requests to greeter RPC server. ```python -import abc -import builtins -import greeting_pb2 -import grpc -import grpc.aio -import typing - -class GreeterServicer(metaclass=abc.ABCMeta): - """RPC service that provides greet functionality""" - - @abc.abstractmethod - async def Greet(self, request: greeting_pb2.GreetRequest, context: grpc.aio.ServicerContext[greeting_pb2.GreetRequest, greeting_pb2.GreetResponse]) -> greeting_pb2.GreetResponse: - """RPC method for greeting""" - ... - -def add_GreeterServicer_to_server(servicer: GreeterServicer, server: grpc.aio.Server) -> None:... - -class GreeterStub: - """RPC service that provides greet functionality""" - - def __init__(self, channel: grpc.aio.Channel) -> None:... - - def Greet(self, request: greeting_pb2.GreetRequest, *, timeout: typing.Optional[builtins.float]=None, metadata: typing.Optional[grpc.aio.MetadataType]=None, credentials: typing.Optional[grpc.CallCredentials]=None, wait_for_ready: typing.Optional[builtins.bool]=None, compression: typing.Optional[grpc.Compression]=None) -> grpc.aio.UnaryUnaryCall[greeting_pb2.GreetRequest, greeting_pb2.GreetResponse]: - """RPC method for greeting""" - ... +import asyncio + +from brokrpc.broker import Broker +from brokrpc.options import ExchangeOptions +from brokrpc.rpc.client import Client +from greeting_pb2 import GreetRequest, GreetResponse +from greeting_brokrpc import GreeterClient, create_client + + +async def main() -> None: + async with Broker("amqp://guest:guest@localhost:5672/", default_exchange=ExchangeOptions(name="test-greet-codegen")) as broker: + client_session = Client(broker) + + greeting_client: GreeterClient + + async with create_client(client_session) as greeting_client: + response = await greeting_client.greet(GreetRequest(name="Bob")) + print(response) + assert isinstance(response.body, GreetResponse) + print(response.body.text) # hello, Bob + + +if __name__ == "__main__": + asyncio.run(main()) ``` diff --git a/poetry.lock b/poetry.lock index 5a591c4..e77c2e5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,44 @@ # This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +[[package]] +name = "aiormq" +version = "6.8.1" +description = "Pure python AMQP asynchronous client library" +category = "dev" +optional = false +python-versions = "<4.0,>=3.8" +files = [ + {file = "aiormq-6.8.1-py3-none-any.whl", hash = "sha256:5da896c8624193708f9409ffad0b20395010e2747f22aa4150593837f40aa017"}, + {file = "aiormq-6.8.1.tar.gz", hash = "sha256:a964ab09634be1da1f9298ce225b310859763d5cf83ef3a7eae1a6dc6bd1da1a"}, +] + +[package.dependencies] +pamqp = "3.3.0" +yarl = "*" + +[[package]] +name = "brokrpc" +version = "0.1.0" +description = "framework for gRPC like server-client communication over message brokers" +category = "dev" +optional = false +python-versions = "^3.12" +files = [] +develop = true + +[package.dependencies] +aiormq = {version = "^6.8.1", optional = true} +yarl = "^1.18.0" + +[package.extras] +aiormq = ["aiormq (>=6.8.1,<7.0.0)"] +cli = ["aiofiles (>=24.1.0,<25.0.0)"] +protobuf = ["googleapis-common-protos (>=1.65.0,<2.0.0)", "protobuf (>=5.26.1,<6.0.0)"] + +[package.source] +type = "directory" +url = "../brokrpc" + [[package]] name = "colorama" version = "0.4.6" @@ -188,6 +227,21 @@ files = [ [package.extras] protobuf = ["grpcio-tools (>=1.68.0)"] +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, +] + +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -200,6 +254,108 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "multidict" +version = "6.1.0" +description = "multidict implementation" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, + {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, + {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, + {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, + {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, + {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, + {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, + {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, + {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, + {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, + {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, + {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, + {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, + {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, + {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, + {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, + {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, + {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, + {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, + {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, + {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, + {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, + {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, + {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, + {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, + {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, + {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, + {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, + {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, + {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, + {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, + {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, + {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, +] + [[package]] name = "mypy" version = "1.13.0" @@ -278,6 +434,22 @@ files = [ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] +[[package]] +name = "pamqp" +version = "3.3.0" +description = "RabbitMQ Focused AMQP low-level library" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pamqp-3.3.0-py2.py3-none-any.whl", hash = "sha256:c901a684794157ae39b52cbf700db8c9aae7a470f13528b9d7b4e5f7202f8eb0"}, + {file = "pamqp-3.3.0.tar.gz", hash = "sha256:40b8795bd4efcf2b0f8821c1de83d12ca16d5760f4507836267fd7a02b06763b"}, +] + +[package.extras] +codegen = ["lxml", "requests", "yapf"] +testing = ["coverage", "flake8", "flake8-comprehensions", "flake8-deprecated", "flake8-import-order", "flake8-print", "flake8-quotes", "flake8-rst-docstrings", "flake8-tuple", "yapf"] + [[package]] name = "pluggy" version = "1.5.0" @@ -294,6 +466,114 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "protobuf" version = "5.28.3" @@ -421,7 +701,104 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] +[[package]] +name = "yarl" +version = "1.18.0" +description = "Yet another URL library" +category = "dev" +optional = false +python-versions = ">=3.9" +files = [ + {file = "yarl-1.18.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:074fee89caab89a97e18ef5f29060ef61ba3cae6cd77673acc54bfdd3214b7b7"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b026cf2c32daf48d90c0c4e406815c3f8f4cfe0c6dfccb094a9add1ff6a0e41a"}, + {file = "yarl-1.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae38bd86eae3ba3d2ce5636cc9e23c80c9db2e9cb557e40b98153ed102b5a736"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:685cc37f3f307c6a8e879986c6d85328f4c637f002e219f50e2ef66f7e062c1d"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8254dbfce84ee5d1e81051ee7a0f1536c108ba294c0fdb5933476398df0654f3"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20de4a8b04de70c49698dc2390b7fd2d18d424d3b876371f9b775e2b462d4b41"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0a2074a37285570d54b55820687de3d2f2b9ecf1b714e482e48c9e7c0402038"}, + {file = "yarl-1.18.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f576ed278860df2721a5d57da3381040176ef1d07def9688a385c8330db61a1"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3a3709450a574d61be6ac53d582496014342ea34876af8dc17cc16da32826c9a"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bd80ed29761490c622edde5dd70537ca8c992c2952eb62ed46984f8eff66d6e8"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:32141e13a1d5a48525e519c9197d3f4d9744d818d5c7d6547524cc9eccc8971e"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8b8d3e4e014fb4274f1c5bf61511d2199e263909fb0b8bda2a7428b0894e8dc6"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:701bb4a8f4de191c8c0cc9a1e6d5142f4df880e9d1210e333b829ca9425570ed"}, + {file = "yarl-1.18.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a45d94075ac0647621eaaf693c8751813a3eccac455d423f473ffed38c8ac5c9"}, + {file = "yarl-1.18.0-cp310-cp310-win32.whl", hash = "sha256:34176bfb082add67cb2a20abd85854165540891147f88b687a5ed0dc225750a0"}, + {file = "yarl-1.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:73553bbeea7d6ec88c08ad8027f4e992798f0abc459361bf06641c71972794dc"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b8e8c516dc4e1a51d86ac975b0350735007e554c962281c432eaa5822aa9765c"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2e6b4466714a73f5251d84b471475850954f1fa6acce4d3f404da1d55d644c34"}, + {file = "yarl-1.18.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c893f8c1a6d48b25961e00922724732d00b39de8bb0b451307482dc87bddcd74"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13aaf2bdbc8c86ddce48626b15f4987f22e80d898818d735b20bd58f17292ee8"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd21c0128e301851de51bc607b0a6da50e82dc34e9601f4b508d08cc89ee7929"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205de377bd23365cd85562c9c6c33844050a93661640fda38e0567d2826b50df"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed69af4fe2a0949b1ea1d012bf065c77b4c7822bad4737f17807af2adb15a73c"}, + {file = "yarl-1.18.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e1c18890091aa3cc8a77967943476b729dc2016f4cfe11e45d89b12519d4a93"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91b8fb9427e33f83ca2ba9501221ffaac1ecf0407f758c4d2f283c523da185ee"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:536a7a8a53b75b2e98ff96edb2dfb91a26b81c4fed82782035767db5a465be46"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a64619a9c47c25582190af38e9eb382279ad42e1f06034f14d794670796016c0"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c73a6bbc97ba1b5a0c3c992ae93d721c395bdbb120492759b94cc1ac71bc6350"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a173401d7821a2a81c7b47d4e7d5c4021375a1441af0c58611c1957445055056"}, + {file = "yarl-1.18.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7520e799b1f84e095cce919bd6c23c9d49472deeef25fe1ef960b04cca51c3fc"}, + {file = "yarl-1.18.0-cp311-cp311-win32.whl", hash = "sha256:c4cb992d8090d5ae5f7afa6754d7211c578be0c45f54d3d94f7781c495d56716"}, + {file = "yarl-1.18.0-cp311-cp311-win_amd64.whl", hash = "sha256:52c136f348605974c9b1c878addd6b7a60e3bf2245833e370862009b86fa4689"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1ece25e2251c28bab737bdf0519c88189b3dd9492dc086a1d77336d940c28ced"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:454902dc1830d935c90b5b53c863ba2a98dcde0fbaa31ca2ed1ad33b2a7171c6"}, + {file = "yarl-1.18.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01be8688fc211dc237e628fcc209dda412d35de7642453059a0553747018d075"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d26f1fa9fa2167bb238f6f4b20218eb4e88dd3ef21bb8f97439fa6b5313e30d"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b234a4a9248a9f000b7a5dfe84b8cb6210ee5120ae70eb72a4dcbdb4c528f72f"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe94d1de77c4cd8caff1bd5480e22342dbd54c93929f5943495d9c1e8abe9f42"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4c90c5363c6b0a54188122b61edb919c2cd1119684999d08cd5e538813a28e"}, + {file = "yarl-1.18.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a98ecadc5a241c9ba06de08127ee4796e1009555efd791bac514207862b43d"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9106025c7f261f9f5144f9aa7681d43867eed06349a7cfb297a1bc804de2f0d1"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f275ede6199d0f1ed4ea5d55a7b7573ccd40d97aee7808559e1298fe6efc8dbd"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f7edeb1dcc7f50a2c8e08b9dc13a413903b7817e72273f00878cb70e766bdb3b"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c083f6dd6951b86e484ebfc9c3524b49bcaa9c420cb4b2a78ef9f7a512bfcc85"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:80741ec5b471fbdfb997821b2842c59660a1c930ceb42f8a84ba8ca0f25a66aa"}, + {file = "yarl-1.18.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1a3297b9cad594e1ff0c040d2881d7d3a74124a3c73e00c3c71526a1234a9f7"}, + {file = "yarl-1.18.0-cp312-cp312-win32.whl", hash = "sha256:cd6ab7d6776c186f544f893b45ee0c883542b35e8a493db74665d2e594d3ca75"}, + {file = "yarl-1.18.0-cp312-cp312-win_amd64.whl", hash = "sha256:039c299a0864d1f43c3e31570045635034ea7021db41bf4842693a72aca8df3a"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6fb64dd45453225f57d82c4764818d7a205ee31ce193e9f0086e493916bd4f72"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3adaaf9c6b1b4fc258584f4443f24d775a2086aee82d1387e48a8b4f3d6aecf6"}, + {file = "yarl-1.18.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da206d1ec78438a563c5429ab808a2b23ad7bc025c8adbf08540dde202be37d5"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:576d258b21c1db4c6449b1c572c75d03f16a482eb380be8003682bdbe7db2f28"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c60e547c0a375c4bfcdd60eef82e7e0e8698bf84c239d715f5c1278a73050393"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3818eabaefb90adeb5e0f62f047310079d426387991106d4fbf3519eec7d90a"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5f72421246c21af6a92fbc8c13b6d4c5427dfd949049b937c3b731f2f9076bd"}, + {file = "yarl-1.18.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7fa7d37f2ada0f42e0723632993ed422f2a679af0e200874d9d861720a54f53e"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:42ba84e2ac26a3f252715f8ec17e6fdc0cbf95b9617c5367579fafcd7fba50eb"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6a49ad0102c0f0ba839628d0bf45973c86ce7b590cdedf7540d5b1833ddc6f00"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:96404e8d5e1bbe36bdaa84ef89dc36f0e75939e060ca5cd45451aba01db02902"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a0509475d714df8f6d498935b3f307cd122c4ca76f7d426c7e1bb791bcd87eda"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1ff116f0285b5c8b3b9a2680aeca29a858b3b9e0402fc79fd850b32c2bcb9f8b"}, + {file = "yarl-1.18.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2580c1d7e66e6d29d6e11855e3b1c6381971e0edd9a5066e6c14d79bc8967af"}, + {file = "yarl-1.18.0-cp313-cp313-win32.whl", hash = "sha256:14408cc4d34e202caba7b5ac9cc84700e3421a9e2d1b157d744d101b061a4a88"}, + {file = "yarl-1.18.0-cp313-cp313-win_amd64.whl", hash = "sha256:1db1537e9cb846eb0ff206eac667f627794be8b71368c1ab3207ec7b6f8c5afc"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fa2c9cb607e0f660d48c54a63de7a9b36fef62f6b8bd50ff592ce1137e73ac7d"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c0f4808644baf0a434a3442df5e0bedf8d05208f0719cedcd499e168b23bfdc4"}, + {file = "yarl-1.18.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7db9584235895a1dffca17e1c634b13870852094f6389b68dcc6338086aa7b08"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f8d27d6f93ceeeb80aa6980e883aa57895270f7f41842b92247e65d7aeddf"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:609ffd44fed2ed88d9b4ef62ee860cf86446cf066333ad4ce4123505b819e581"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f172b8b2c72a13a06ea49225a9c47079549036ad1b34afa12d5491b881f5b993"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d89ae7de94631b60d468412c18290d358a9d805182373d804ec839978b120422"}, + {file = "yarl-1.18.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:466d31fd043ef9af822ee3f1df8fdff4e8c199a7f4012c2642006af240eade17"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7609b8462351c4836b3edce4201acb6dd46187b207c589b30a87ffd1813b48dc"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d9d4f5e471e8dc49b593a80766c2328257e405f943c56a3dc985c125732bc4cf"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:67b336c15e564d76869c9a21316f90edf546809a5796a083b8f57c845056bc01"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b212452b80cae26cb767aa045b051740e464c5129b7bd739c58fbb7deb339e7b"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:38b39b7b3e692b6c92b986b00137a3891eddb66311b229d1940dcbd4f025083c"}, + {file = "yarl-1.18.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a7ee6884a8848792d58b854946b685521f41d8871afa65e0d4a774954e9c9e89"}, + {file = "yarl-1.18.0-cp39-cp39-win32.whl", hash = "sha256:b4095c5019bb889aa866bf12ed4c85c0daea5aafcb7c20d1519f02a1e738f07f"}, + {file = "yarl-1.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:2d90f2e4d16a5b0915ee065218b435d2ef619dd228973b1b47d262a6f7cd8fa5"}, + {file = "yarl-1.18.0-py3-none-any.whl", hash = "sha256:dbf53db46f7cf176ee01d8d98c39381440776fcda13779d269a8ba664f69bec0"}, + {file = "yarl-1.18.0.tar.gz", hash = "sha256:20d95535e7d833889982bfe7cc321b7f63bf8879788fee982c76ae2b24cfb715"}, +] + +[package.dependencies] +idna = ">=2.0" +multidict = ">=4.0" +propcache = ">=0.2.0" + [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "004fc4dddfd066668a15a55954d03916da7fd0d707febd0461a0bd33d9947c0d" +content-hash = "b39a0619bd7665abf08c4cd29cb05f5c8af5af095e440d42518f2f302e4ab4a5" diff --git a/pyproject.toml b/pyproject.toml index d64566b..6616a75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,8 @@ classifiers = [ ] [tool.poetry.scripts] -protoc-gen-pyprotostuben = "pyprotostuben.protoc:gen_mypy_stub" +protoc-gen-mypy-stub = "pyprotostuben.protoc:gen_mypy_stub" +protoc-gen-brokrpc = "pyprotostuben.protoc:gen_brokrpc" protoc-gen-echo = "pyprotostuben.protoc:echo" [tool.poetry.dependencies] @@ -27,6 +28,8 @@ pytest = "^8.3.3" pytest-cov = "^6.0.0" ruff = "^0.7.4" grpc-stubs = "^1.53.0.5" +# TODO: specify pypi package version +brokrpc = { path = "../brokrpc", extras = ["aiormq"], develop = true, python = "^3.12" } [build-system] @@ -38,6 +41,7 @@ include = ["src/**/*.py", "tests/**/*.py"] extend-exclude = ["tests/**/expected_gen/**.py"] force-exclude = true line-length = 120 +output-format = "pylint" [tool.ruff.lint] select = ["ALL"] diff --git a/src/pyprotostuben/codegen/brokrpc/__init__.py b/src/pyprotostuben/codegen/brokrpc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/pyprotostuben/codegen/brokrpc/generator.py b/src/pyprotostuben/codegen/brokrpc/generator.py new file mode 100644 index 0000000..59b1f97 --- /dev/null +++ b/src/pyprotostuben/codegen/brokrpc/generator.py @@ -0,0 +1,354 @@ +import ast +import typing as t +from dataclasses import dataclass, field +from functools import cached_property + +from pyprotostuben.codegen.module_ast import ModuleASTContext +from pyprotostuben.logging import LoggerMixin +from pyprotostuben.protobuf.builder.grpc import MethodInfo +from pyprotostuben.protobuf.registry import TypeRegistry +from pyprotostuben.protobuf.visitor.decorator import ProtoVisitorDecorator +from pyprotostuben.protobuf.visitor.model import ( + DescriptorContext, + EnumDescriptorContext, + EnumValueDescriptorContext, + FieldDescriptorContext, + FileDescriptorContext, + MethodDescriptorContext, + OneofDescriptorContext, + ServiceDescriptorContext, +) +from pyprotostuben.python.ast_builder import ASTBuilder +from pyprotostuben.python.info import ModuleInfo, PackageInfo, TypeInfo +from pyprotostuben.stack import MutableStack +from pyprotostuben.string_case import camel2snake + + +@dataclass() +class Scope: + methods: t.MutableSequence[MethodInfo] = field(default_factory=list) + body: t.MutableSequence[ast.stmt] = field(default_factory=list) + + +@dataclass() +class BrokRPCContext(ModuleASTContext): + builder: ASTBuilder + module: ModuleInfo + deps: t.MutableSet[ModuleInfo] + scopes: MutableStack[Scope] + + +class BrokRPCModuleGenerator(ProtoVisitorDecorator[BrokRPCContext], LoggerMixin): + def __init__(self, registry: TypeRegistry) -> None: + self.__registry = registry + + def enter_file_descriptor_proto(self, context: FileDescriptorContext[BrokRPCContext]) -> None: + context.meta.scopes.put(Scope()) + + def leave_file_descriptor_proto(self, context: FileDescriptorContext[BrokRPCContext]) -> None: + scope = context.meta.scopes.pop() + + if scope.body: + context.meta.modules.update( + { + context.meta.module.file: context.meta.builder.build_module( + deps=context.meta.deps, + doc=f"Source: {context.file.proto_path}", + body=scope.body, + ), + } + ) + + def enter_enum_descriptor_proto(self, context: EnumDescriptorContext[BrokRPCContext]) -> None: + pass + + def leave_enum_descriptor_proto(self, context: EnumDescriptorContext[BrokRPCContext]) -> None: + pass + + def enter_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[BrokRPCContext]) -> None: + pass + + def leave_enum_value_descriptor_proto(self, context: EnumValueDescriptorContext[BrokRPCContext]) -> None: + pass + + def enter_descriptor_proto(self, context: DescriptorContext[BrokRPCContext]) -> None: + pass + + def leave_descriptor_proto(self, context: DescriptorContext[BrokRPCContext]) -> None: + pass + + def enter_oneof_descriptor_proto(self, context: OneofDescriptorContext[BrokRPCContext]) -> None: + pass + + def leave_oneof_descriptor_proto(self, context: OneofDescriptorContext[BrokRPCContext]) -> None: + pass + + def enter_field_descriptor_proto(self, context: FieldDescriptorContext[BrokRPCContext]) -> None: + pass + + def leave_field_descriptor_proto(self, context: FieldDescriptorContext[BrokRPCContext]) -> None: + pass + + def enter_service_descriptor_proto(self, context: ServiceDescriptorContext[BrokRPCContext]) -> None: + context.meta.scopes.put(Scope()) + + def leave_service_descriptor_proto(self, context: ServiceDescriptorContext[BrokRPCContext]) -> None: + scope = context.meta.scopes.pop() + parent = context.meta.scopes.get_last() + + service_class_name = f"{context.item.name}Service" + client_class_name = f"{context.item.name}Client" + + parent.body.extend( + [ + self.__build_service_def(context, service_class_name, scope.methods), + self.__build_service_registrator_def(context, service_class_name, scope.methods), + self.__build_client_def(context, client_class_name, scope.methods), + self.__build_client_factory_def(context, client_class_name, scope.methods), + ] + ) + + def enter_method_descriptor_proto(self, context: MethodDescriptorContext[BrokRPCContext]) -> None: + pass + + def leave_method_descriptor_proto(self, context: MethodDescriptorContext[BrokRPCContext]) -> None: + scope = context.meta.scopes.get_last() + + builder = context.meta.builder + + scope.methods.append( + MethodInfo( + name=camel2snake(context.item.name), + doc="\n\n".join(context.comments), + client_input=builder.build_ref(self.__registry.resolve_proto_method_client_input(context.item)), + client_streaming=False, + server_output=builder.build_ref(self.__registry.resolve_proto_method_server_output(context.item)), + server_streaming=False, + ) + ) + + def __build_service_def( + self, + context: ServiceDescriptorContext[BrokRPCContext], + name: str, + methods: t.Sequence[MethodInfo], + ) -> ast.stmt: + builder = context.meta.builder + + return builder.build_abstract_class_def( + name=name, + doc="\n\n".join(context.comments), + body=[ + builder.build_abstract_method_def( + name=method.name, + args=[ + builder.build_pos_arg( + name="request", + annotation=builder.build_generic_ref(self.__brokrpc_request, method.client_input), + ) + ], + returns=method.server_output, + is_async=True, + doc=method.doc, + ) + for method in methods + ], + ) + + def __build_service_registrator_def( + self, + context: ServiceDescriptorContext[BrokRPCContext], + name: str, + methods: t.Sequence[MethodInfo], + ) -> ast.stmt: + builder = context.meta.builder + + return builder.build_func_def( + name=f"add_{camel2snake(name)}_to_server", + args=[ + builder.build_pos_arg( + name="service", + annotation=builder.build_name(name), + ), + builder.build_pos_arg( + name="server", + annotation=builder.build_ref(self.__brokrpc_server), + ), + ], + returns=builder.build_none_ref(), + body=[ + builder.build_call_stmt( + func=builder.build_name("server", "register_unary_unary_handler"), + kwargs={ + "func": builder.build_name("service", method.name), + "routing_key": self.__build_routing_key(context, method), + "serializer": self.__build_serializer(builder, method), + }, + ) + for method in methods + ], + ) + + def __build_client_def( + self, + context: ServiceDescriptorContext[BrokRPCContext], + name: str, + methods: t.Sequence[MethodInfo], + ) -> ast.stmt: + builder = context.meta.builder + + return builder.build_class_def( + name=name, + doc="\n\n".join(context.comments), + body=( + self.__build_client_init(builder, methods), + *(self.__build_client_call(builder, method) for method in methods), + ), + ) + + def __build_client_init(self, builder: ASTBuilder, methods: t.Sequence[MethodInfo]) -> ast.stmt: + return builder.build_init_def( + args=[ + builder.build_pos_arg( + name=method.name, + annotation=builder.build_generic_ref( + self.__brokrpc_caller, + method.client_input, + method.server_output, + ), + ) + for method in methods + ], + body=[ + builder.build_attr_assign( + target=builder.build_name("self", f"__{method.name}"), + value=builder.build_name(method.name), + ) + for method in methods + ], + ) + + def __build_client_call(self, builder: ASTBuilder, method: MethodInfo) -> ast.stmt: + return builder.build_method_def( + name=method.name, + args=[ + builder.build_pos_arg( + name="request", + annotation=method.client_input, + ), + ], + returns=builder.build_generic_ref(self.__brokrpc_response, method.server_output), + doc=method.doc, + body=[ + builder.build_return_stmt( + builder.build_call( + func=builder.build_name("self", f"__{method.name}", "invoke"), + args=[builder.build_name("request")], + is_async=True, + ) + ), + ], + is_async=True, + ) + + def __build_client_factory_def( + self, + context: ServiceDescriptorContext[BrokRPCContext], + name: str, + methods: t.Sequence[MethodInfo], + ) -> ast.stmt: + builder = context.meta.builder + + return builder.build_func_def( + name="create_client", + args=[ + builder.build_pos_arg( + name="client", + annotation=builder.build_ref(self.__brokrpc_client), + ), + ], + returns=builder.build_name(name), + is_async=True, + is_context_manager=True, + body=[ + builder.build_with_stmt( + is_async=True, + items=[ + ( + method.name, + self.__build_client_caller_factory(context, method), + ) + for method in methods + ], + body=[ + builder.build_yield_stmt( + builder.build_call( + func=builder.build_name(name), + kwargs={method.name: builder.build_name(method.name) for method in methods}, + ) + ) + ], + ), + ], + ) + + def __build_client_caller_factory( + self, + context: ServiceDescriptorContext[BrokRPCContext], + method: MethodInfo, + ) -> ast.expr: + builder = context.meta.builder + + return builder.build_call( + func=builder.build_name("client", "unary_unary_caller"), + kwargs={ + "routing_key": self.__build_routing_key(context, method), + "serializer": self.__build_serializer(builder, method), + }, + ) + + def __build_routing_key(self, context: ServiceDescriptorContext[BrokRPCContext], method: MethodInfo) -> ast.expr: + return ast.Constant(value=f"/{context.root.package}/{context.item.name}/{method.name}") + + def __build_serializer(self, builder: ASTBuilder, method: MethodInfo) -> ast.expr: + return builder.build_call( + func=builder.build_ref(self.__brokrpc_serializer), + args=[ + method.client_input, + method.server_output, + ], + ) + + @cached_property + def __brokrpc(self) -> PackageInfo: + return PackageInfo(None, "brokrpc") + + @cached_property + def __brokrpc_rpc(self) -> PackageInfo: + return PackageInfo(self.__brokrpc, "rpc") + + @cached_property + def __brokrpc_server(self) -> TypeInfo: + return TypeInfo.build(ModuleInfo(self.__brokrpc_rpc, "server"), "Server") + + @cached_property + def __brokrpc_client(self) -> TypeInfo: + return TypeInfo.build(ModuleInfo(self.__brokrpc_rpc, "client"), "Client") + + @cached_property + def __brokrpc_caller(self) -> TypeInfo: + return TypeInfo.build(ModuleInfo(self.__brokrpc_rpc, "abc"), "Caller") + + @cached_property + def __brokrpc_request(self) -> TypeInfo: + return TypeInfo.build(ModuleInfo(self.__brokrpc_rpc, "model"), "Request") + + @cached_property + def __brokrpc_response(self) -> TypeInfo: + return TypeInfo.build(ModuleInfo(self.__brokrpc_rpc, "model"), "Response") + + @cached_property + def __brokrpc_serializer(self) -> TypeInfo: + return TypeInfo.build( + ModuleInfo(PackageInfo(self.__brokrpc, "serializer"), "protobuf"), "RPCProtobufSerializer" + ) diff --git a/src/pyprotostuben/codegen/brokrpc/plugin.py b/src/pyprotostuben/codegen/brokrpc/plugin.py new file mode 100644 index 0000000..086c7d2 --- /dev/null +++ b/src/pyprotostuben/codegen/brokrpc/plugin.py @@ -0,0 +1,83 @@ +from contextlib import ExitStack + +from google.protobuf.compiler.plugin_pb2 import CodeGeneratorRequest, CodeGeneratorResponse +from google.protobuf.descriptor_pb2 import GeneratedCodeInfo + +from pyprotostuben.codegen.abc import ProtocPlugin, ProtoFileGenerator +from pyprotostuben.codegen.brokrpc.generator import BrokRPCContext, BrokRPCModuleGenerator +from pyprotostuben.codegen.model import GeneratedItem +from pyprotostuben.codegen.module_ast import ModuleASTBasedProtoFileGenerator +from pyprotostuben.logging import LoggerMixin +from pyprotostuben.pool.abc import Pool +from pyprotostuben.pool.process import MultiProcessPool, SingleProcessPool +from pyprotostuben.protobuf.builder.resolver import ProtoDependencyResolver +from pyprotostuben.protobuf.context import CodeGeneratorContext, ContextBuilder +from pyprotostuben.protobuf.file import ProtoFile +from pyprotostuben.protobuf.parser import CodeGeneratorParameters +from pyprotostuben.python.ast_builder import ASTBuilder +from pyprotostuben.python.info import ModuleInfo +from pyprotostuben.stack import MutableStack + + +class BrokRPCProtocPlugin(ProtocPlugin, LoggerMixin): + def run(self, request: CodeGeneratorRequest) -> CodeGeneratorResponse: + log = self._log.bind_details(request_file_to_generate=request.file_to_generate) + log.debug("request received") + + with ExitStack() as cm_stack: + context = ContextBuilder.build(request) + gen = self.__create_generator(context) + pool = self.__create_pool(context.params, cm_stack) + + resp = CodeGeneratorResponse( + supported_features=CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL, + file=(self.__build_file(item) for items in pool.run(gen.run, context.files) for item in items), + ) + + log.info("request handled") + + return resp + + def __create_generator(self, context: CodeGeneratorContext) -> ProtoFileGenerator: + return ModuleASTBasedProtoFileGenerator( + context_factory=_MultiProcessFuncs.create_visitor_context, + visitor=BrokRPCModuleGenerator(registry=context.registry), + ) + + def __create_pool(self, params: CodeGeneratorParameters, cm_stack: ExitStack) -> Pool: + return ( + SingleProcessPool() + if params.has_flag("no-parallel") or params.has_flag("debug") + else cm_stack.enter_context(MultiProcessPool.setup()) + ) + + def __build_file(self, item: GeneratedItem) -> CodeGeneratorResponse.File: + return CodeGeneratorResponse.File( + name=str(item.path), + generated_code_info=GeneratedCodeInfo( + annotation=[GeneratedCodeInfo.Annotation(source_file=str(item.source.proto_path))], + ), + content=item.content, + ) + + +class _MultiProcessFuncs: + """ + A set of picklable functions that can be passed to `MultiProcessPool`. + + For more info: https://docs.python.org/3/library/multiprocessing.html#programming-guidelines + """ + + @staticmethod + def create_visitor_context(file: ProtoFile) -> BrokRPCContext: + deps = set[ModuleInfo]() + module = ModuleInfo(file.pb2_package, f"{file.name}_brokrpc") + + return BrokRPCContext( + file=file, + modules={}, + deps=deps, + module=module, + builder=ASTBuilder(ProtoDependencyResolver(module, deps)), + scopes=MutableStack(), + ) diff --git a/src/pyprotostuben/codegen/module_ast.py b/src/pyprotostuben/codegen/module_ast.py index f06a57f..2462fb2 100644 --- a/src/pyprotostuben/codegen/module_ast.py +++ b/src/pyprotostuben/codegen/module_ast.py @@ -11,7 +11,7 @@ from pyprotostuben.protobuf.visitor.walker import Walker -@dataclass(frozen=True) +@dataclass() class ModuleASTContext: file: ProtoFile modules: t.MutableMapping[Path, ast.Module] diff --git a/src/pyprotostuben/codegen/mypy/generator.py b/src/pyprotostuben/codegen/mypy/generator.py index 36e5a22..024c69f 100644 --- a/src/pyprotostuben/codegen/mypy/generator.py +++ b/src/pyprotostuben/codegen/mypy/generator.py @@ -24,7 +24,7 @@ from pyprotostuben.stack import MutableStack -@dataclass(frozen=True) +@dataclass() class MypyStubContext(ModuleASTContext): messages: MutableStack[MessageContext] grpcs: MutableStack[GRPCContext] diff --git a/src/pyprotostuben/protobuf/visitor/model.py b/src/pyprotostuben/protobuf/visitor/model.py index 33a7ce7..4024d08 100644 --- a/src/pyprotostuben/protobuf/visitor/model.py +++ b/src/pyprotostuben/protobuf/visitor/model.py @@ -89,6 +89,22 @@ def parts(self) -> t.Sequence[Proto]: def location(self) -> t.Optional[SourceCodeInfo.Location]: return self.root_context.locations.get(self.path) + @property + def comments(self) -> t.Sequence[str]: + if self.location is None: + return [] + + blocks: t.List[str] = [] + blocks.extend(comment.strip() for comment in self.location.leading_detached_comments) + + if self.location.HasField("leading_comments"): + blocks.append(self.location.leading_comments.strip()) + + if self.location.HasField("trailing_comments"): + blocks.append(self.location.trailing_comments.strip()) + + return blocks + @dataclass(frozen=True) class EnumDescriptorContext(ChildContext[M_co, EnumDescriptorProto, t.Union[FileDescriptorProto, DescriptorProto]]): diff --git a/src/pyprotostuben/protoc.py b/src/pyprotostuben/protoc.py index dc7a944..ecd02d9 100644 --- a/src/pyprotostuben/protoc.py +++ b/src/pyprotostuben/protoc.py @@ -9,6 +9,13 @@ def gen_mypy_stub() -> None: run_codegen(MypyStubProtocPlugin()) +def gen_brokrpc() -> None: + from pyprotostuben.codegen.brokrpc.plugin import BrokRPCProtocPlugin + + Logger.configure() + run_codegen(BrokRPCProtocPlugin()) + + def echo() -> None: from pyprotostuben.codegen.echo import RequestEchoProtocPlugin diff --git a/src/pyprotostuben/python/ast_builder.py b/src/pyprotostuben/python/ast_builder.py index fd9eb5d..1318d71 100644 --- a/src/pyprotostuben/python/ast_builder.py +++ b/src/pyprotostuben/python/ast_builder.py @@ -62,6 +62,9 @@ def build_name(self, head: str, *tail: str) -> ast.expr: return expr + def build_docstring(self, *lines: str) -> ast.stmt: + return ast.Expr(value=ast.Constant(value="\n".join(lines))) + def build_pos_arg(self, name: str, annotation: TypeRef, default: t.Optional[ast.expr] = None) -> FuncArgInfo: return FuncArgInfo( name=name, @@ -78,7 +81,7 @@ def build_kw_arg(self, name: str, annotation: TypeRef, default: t.Optional[ast.e default=default, ) - def build_func( + def build_func_def( self, *, name: str, @@ -130,7 +133,7 @@ def build_func_stub( is_async: bool = False, is_context_manager: bool = False, ) -> ast.stmt: - return self.build_func( + return self.build_func_def( name=name, decorators=decorators, args=args, @@ -180,7 +183,7 @@ def build_abstract_class_def( body=body, ) - def build_method( + def build_method_def( self, *, name: str, @@ -192,7 +195,7 @@ def build_method( is_async: bool = False, is_context_manager: bool = False, ) -> ast.stmt: - return self.build_func( + return self.build_func_def( name=name, decorators=decorators, args=[FuncArgInfo(name="self", kind=FuncArgInfo.Kind.POS, annotation=None, default=None), *(args or [])], @@ -214,7 +217,7 @@ def build_method_stub( is_async: bool = False, is_context_manager: bool = False, ) -> ast.stmt: - return self.build_method( + return self.build_method_def( name=name, decorators=decorators, args=args, @@ -225,7 +228,7 @@ def build_method_stub( is_context_manager=is_context_manager, ) - def build_abstract_method( + def build_abstract_method_def( self, *, name: str, @@ -235,7 +238,7 @@ def build_abstract_method( is_async: bool = False, is_context_manager: bool = False, ) -> ast.stmt: - return self.build_method( + return self.build_method_def( name=name, decorators=[TypeInfo.build(ModuleInfo(None, "abc"), "abstractmethod")], args=args, @@ -264,6 +267,29 @@ def build_abstract_method_stub( is_async=is_async, ) + def build_class_method_def( + self, + *, + name: str, + decorators: t.Optional[t.Sequence[TypeRef]] = None, + args: t.Optional[t.Sequence[FuncArgInfo]] = None, + returns: TypeRef, + doc: t.Optional[str] = None, + body: t.Sequence[ast.stmt], + is_async: bool = False, + is_context_manager: bool = False, + ) -> ast.stmt: + return self.build_func_def( + name=name, + decorators=[*(decorators or ()), TypeInfo.build(self.builtins_module, "classmethod")], + args=[FuncArgInfo(name="cls", kind=FuncArgInfo.Kind.POS, annotation=None, default=None), *(args or [])], + returns=returns, + doc=doc, + body=body, + is_async=is_async, + is_context_manager=is_context_manager, + ) + def build_property_getter_stub( self, *, @@ -295,13 +321,13 @@ def build_property_setter_stub( is_async=False, ) - def build_init( + def build_init_def( self, args: t.Sequence[FuncArgInfo], body: t.Sequence[ast.stmt], doc: t.Optional[str] = None, ) -> ast.stmt: - return self.build_method( + return self.build_method_def( name="__init__", args=args, body=body, @@ -315,7 +341,7 @@ def build_init_stub( args: t.Sequence[FuncArgInfo], doc: t.Optional[str] = None, ) -> ast.stmt: - return self.build_init(args=args, body=self._build_stub_body(doc), doc=doc) + return self.build_init_def(args=args, body=self._build_stub_body(doc), doc=doc) def build_attr_stub( self, @@ -332,31 +358,82 @@ def build_attr_stub( simple=1, ) + def build_attr_assign(self, target: TypeRef, value: TypeRef) -> ast.stmt: + return ast.Assign( + targets=[self.build_ref(target)], + value=self.build_ref(value), + # NOTE: Seems like it is allowed to pass `None`, but ast typing says it's not. + lineno=t.cast(int, None), + ) + def build_call( self, + *, func: TypeRef, - args: t.Optional[t.Sequence[ast.expr]] = None, - kwargs: t.Optional[t.Mapping[str, ast.expr]] = None, + args: t.Optional[t.Sequence[TypeRef]] = None, + kwargs: t.Optional[t.Mapping[str, TypeRef]] = None, + is_async: bool = False, ) -> ast.expr: - return ast.Call( + expr = ast.Call( func=self.build_ref(func), - args=list(args or ()), + args=[self.build_ref(arg) for arg in (args or ())], keywords=[ ast.keyword( arg=key, - value=value, + value=self.build_ref(value), ) for key, value in (kwargs or {}).items() ], ) + return ast.Await(value=expr) if is_async else expr + def build_call_stmt( self, + *, func: TypeRef, - args: t.Optional[t.Sequence[ast.expr]] = None, - kwargs: t.Optional[t.Mapping[str, ast.expr]] = None, + args: t.Optional[t.Sequence[TypeRef]] = None, + kwargs: t.Optional[t.Mapping[str, TypeRef]] = None, + is_async: bool = False, ) -> ast.stmt: - return ast.Expr(value=self.build_call(func=func, args=args, kwargs=kwargs)) + return ast.Expr(value=self.build_call(func=func, args=args, kwargs=kwargs, is_async=is_async)) + + def build_with_stmt( + self, + *, + items: t.Sequence[t.Tuple[str, TypeRef]], + body: t.Sequence[ast.stmt], + is_async: bool = False, + ) -> ast.stmt: + with_items = [ + ast.withitem( + context_expr=self.build_ref(expr), + optional_vars=ast.Name(id=name), + ) + for name, expr in items + ] + + return ( + ast.AsyncWith( + items=with_items, + body=list(body), + # NOTE: Seems like it is allowed to pass `None`, but ast typing says it's not. + lineno=t.cast(int, None), + ) + if is_async + else ast.With( + items=with_items, + body=list(body), + # NOTE: Seems like it is allowed to pass `None`, but ast typing says it's not. + lineno=t.cast(int, None), + ) + ) + + def build_yield_stmt(self, value: ast.expr) -> ast.stmt: + return ast.Expr(value=ast.Yield(value=value)) + + def build_return_stmt(self, value: ast.expr) -> ast.stmt: + return ast.Return(value=value) def build_context_manager_decorator_ref(self, *, is_async: bool = False) -> ast.expr: return self.build_ref( @@ -499,13 +576,6 @@ def _build_body(self, doc: t.Optional[str], body: t.Optional[t.Sequence[ast.stmt return result - def build_docstring(self, *lines: str) -> ast.stmt: - return ast.Expr( - value=ast.Constant( - value="\n".join(lines), - ), - ) - def _build_stub_body(self, doc: t.Optional[str]) -> t.List[ast.stmt]: return ( [ diff --git a/src/pyprotostuben/string_case.py b/src/pyprotostuben/string_case.py new file mode 100644 index 0000000..22ff9b2 --- /dev/null +++ b/src/pyprotostuben/string_case.py @@ -0,0 +1,12 @@ +import re +import typing as t +from functools import cache + + +@cache +def _get_camel2snake_pattern() -> t.Pattern[str]: + return re.compile(r"(? str: + return _get_camel2snake_pattern().sub("_", value).lower() diff --git a/tests/integration/cases/case_000_greeting/case.py b/tests/integration/cases/case_000_greeting/case.py index 7bf4e80..692e1fa 100644 --- a/tests/integration/cases/case_000_greeting/case.py +++ b/tests/integration/cases/case_000_greeting/case.py @@ -1,5 +1,11 @@ +from pyprotostuben.codegen.brokrpc.plugin import BrokRPCProtocPlugin from pyprotostuben.codegen.mypy.plugin import MypyStubProtocPlugin from tests.integration.cases.case import DirCaseProvider -mypy_case = DirCaseProvider(__file__, MypyStubProtocPlugin(), "no-parallel") -mypy_case_multiprocessing = DirCaseProvider(__file__, MypyStubProtocPlugin()) +mypy_stub_paths = ["greeting_pb2.pyi", "greeting_pb2_grpc.pyi"] +mypy_case = DirCaseProvider(__file__, MypyStubProtocPlugin(), "no-parallel", expected_gen_paths=mypy_stub_paths) +mypy_case_multiprocessing = DirCaseProvider(__file__, MypyStubProtocPlugin(), expected_gen_paths=mypy_stub_paths) + +brokrpc_case = DirCaseProvider( + __file__, BrokRPCProtocPlugin(), "no-parallel", expected_gen_paths=["greeting_brokrpc.py"] +) diff --git a/tests/integration/cases/case_000_greeting/expected_gen/greeting_brokrpc.py b/tests/integration/cases/case_000_greeting/expected_gen/greeting_brokrpc.py new file mode 100644 index 0000000..ea23796 --- /dev/null +++ b/tests/integration/cases/case_000_greeting/expected_gen/greeting_brokrpc.py @@ -0,0 +1,32 @@ +"""Source: greeting.proto""" +import abc +import brokrpc.rpc.abc +import brokrpc.rpc.client +import brokrpc.rpc.model +import brokrpc.rpc.server +import brokrpc.serializer.protobuf +import contextlib +import greeting_pb2 +import typing + +class GreeterService(metaclass=abc.ABCMeta): + + @abc.abstractmethod + async def greet(self, request: brokrpc.rpc.model.Request[greeting_pb2.GreetRequest]) -> greeting_pb2.GreetResponse: + raise NotImplementedError + +def add_greeter_service_to_server(service: GreeterService, server: brokrpc.rpc.server.Server) -> None: + server.register_unary_unary_handler(func=service.greet, routing_key='/greeting/Greeter/greet', serializer=brokrpc.serializer.protobuf.RPCProtobufSerializer(greeting_pb2.GreetRequest, greeting_pb2.GreetResponse)) + +class GreeterClient: + + def __init__(self, greet: brokrpc.rpc.abc.Caller[greeting_pb2.GreetRequest, greeting_pb2.GreetResponse]) -> None: + self.__greet = greet + + async def greet(self, request: greeting_pb2.GreetRequest) -> brokrpc.rpc.model.Response[greeting_pb2.GreetResponse]: + return await self.__greet.invoke(request) + +@contextlib.asynccontextmanager +async def create_client(client: brokrpc.rpc.client.Client) -> typing.AsyncIterator[GreeterClient]: + async with client.unary_unary_caller(routing_key='/greeting/Greeter/greet', serializer=brokrpc.serializer.protobuf.RPCProtobufSerializer(greeting_pb2.GreetRequest, greeting_pb2.GreetResponse)) as greet: + yield GreeterClient(greet=greet) \ No newline at end of file From 190dce1628da45a4411dc8a40780bd9ffcb3b07c Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 00:53:28 +0100 Subject: [PATCH 3/9] bump minor version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 6616a75..d3536cc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pyprotostuben" -version = "0.2.1" +version = "0.3.0" description = "Generate Python MyPy stub modules from protobuf files." authors = ["zerlok "] readme = "README.md" From 82c8776ee7a534150d807f7fdcd1985e0345af28 Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 01:44:02 +0100 Subject: [PATCH 4/9] add publish BrokRPC version --- poetry.lock | 511 +++++++++++++++++++++++++++++++++++++++++++++---- pyproject.toml | 15 +- 2 files changed, 488 insertions(+), 38 deletions(-) diff --git a/poetry.lock b/poetry.lock index e77c2e5..20dac6e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,20 +1,24 @@ # This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] -name = "aiormq" -version = "6.8.1" -description = "Pure python AMQP asynchronous client library" +name = "attrs" +version = "24.2.0" +description = "Classes Without Boilerplate" category = "dev" optional = false -python-versions = "<4.0,>=3.8" +python-versions = ">=3.7" files = [ - {file = "aiormq-6.8.1-py3-none-any.whl", hash = "sha256:5da896c8624193708f9409ffad0b20395010e2747f22aa4150593837f40aa017"}, - {file = "aiormq-6.8.1.tar.gz", hash = "sha256:a964ab09634be1da1f9298ce225b310859763d5cf83ef3a7eae1a6dc6bd1da1a"}, + {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, + {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] -[package.dependencies] -pamqp = "3.3.0" -yarl = "*" +[package.extras] +benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] +tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "brokrpc" @@ -22,23 +26,20 @@ version = "0.1.0" description = "framework for gRPC like server-client communication over message brokers" category = "dev" optional = false -python-versions = "^3.12" -files = [] -develop = true +python-versions = "<4.0,>=3.12" +files = [ + {file = "brokrpc-0.1.0-py3-none-any.whl", hash = "sha256:75b57dd6d53769b372d5a24665158d6de4ad38287581d3ae7c059447fc13b8e9"}, + {file = "brokrpc-0.1.0.tar.gz", hash = "sha256:de5242e40e1bfe92a29f6dc87f87ec1e30ac824a999b44c14791f6b998e39b1d"}, +] [package.dependencies] -aiormq = {version = "^6.8.1", optional = true} -yarl = "^1.18.0" +yarl = ">=1.18.0,<2.0.0" [package.extras] aiormq = ["aiormq (>=6.8.1,<7.0.0)"] cli = ["aiofiles (>=24.1.0,<25.0.0)"] protobuf = ["googleapis-common-protos (>=1.65.0,<2.0.0)", "protobuf (>=5.26.1,<6.0.0)"] -[package.source] -type = "directory" -url = "../brokrpc" - [[package]] name = "colorama" version = "0.4.6" @@ -129,6 +130,18 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +category = "dev" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -254,6 +267,132 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsonschema" +version = "4.23.0" +description = "An implementation of JSON Schema validation for Python" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] + +[[package]] +name = "jsonschema-specifications" +version = "2024.10.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +category = "dev" +optional = false +python-versions = ">=3.9" +files = [ + {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, + {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "markupsafe" +version = "3.0.2" +description = "Safely add untrusted strings to HTML/XML markup." +category = "dev" +optional = false +python-versions = ">=3.9" +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + [[package]] name = "multidict" version = "6.1.0" @@ -434,22 +573,6 @@ files = [ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -[[package]] -name = "pamqp" -version = "3.3.0" -description = "RabbitMQ Focused AMQP low-level library" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pamqp-3.3.0-py2.py3-none-any.whl", hash = "sha256:c901a684794157ae39b52cbf700db8c9aae7a470f13528b9d7b4e5f7202f8eb0"}, - {file = "pamqp-3.3.0.tar.gz", hash = "sha256:40b8795bd4efcf2b0f8821c1de83d12ca16d5760f4507836267fd7a02b06763b"}, -] - -[package.extras] -codegen = ["lxml", "requests", "yapf"] -testing = ["coverage", "flake8", "flake8-comprehensions", "flake8-deprecated", "flake8-import-order", "flake8-print", "flake8-quotes", "flake8-rst-docstrings", "flake8-tuple", "yapf"] - [[package]] name = "pluggy" version = "1.5.0" @@ -637,6 +760,312 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] +[[package]] +name = "pytest-mypy-plugins" +version = "3.1.2" +description = "pytest plugin for writing tests for mypy plugins" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mypy-plugins-3.1.2.tar.gz", hash = "sha256:14fa9b00e59713a6fdb88fcf04e8139b9467e117b98d61fc12038c60afb7febe"}, + {file = "pytest_mypy_plugins-3.1.2-py3-none-any.whl", hash = "sha256:3478ccb68e26a159e1287c4614c60f84cd0720e3895f174365c7440498234b9f"}, +] + +[package.dependencies] +decorator = "*" +Jinja2 = "*" +jsonschema = "*" +mypy = ">=1.3" +packaging = "*" +pytest = ">=7.0.0" +pyyaml = "*" +regex = "*" +tomlkit = ">=0.11" + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, +] + +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "regex" +version = "2024.11.6" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, +] + +[[package]] +name = "rpds-py" +version = "0.21.0" +description = "Python bindings to Rust's persistent data structures (rpds)" +category = "dev" +optional = false +python-versions = ">=3.9" +files = [ + {file = "rpds_py-0.21.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a017f813f24b9df929674d0332a374d40d7f0162b326562daae8066b502d0590"}, + {file = "rpds_py-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:20cc1ed0bcc86d8e1a7e968cce15be45178fd16e2ff656a243145e0b439bd250"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad116dda078d0bc4886cb7840e19811562acdc7a8e296ea6ec37e70326c1b41c"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:808f1ac7cf3b44f81c9475475ceb221f982ef548e44e024ad5f9e7060649540e"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de552f4a1916e520f2703ec474d2b4d3f86d41f353e7680b597512ffe7eac5d0"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:efec946f331349dfc4ae9d0e034c263ddde19414fe5128580f512619abed05f1"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b80b4690bbff51a034bfde9c9f6bf9357f0a8c61f548942b80f7b66356508bf5"}, + {file = "rpds_py-0.21.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:085ed25baac88953d4283e5b5bd094b155075bb40d07c29c4f073e10623f9f2e"}, + {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:daa8efac2a1273eed2354397a51216ae1e198ecbce9036fba4e7610b308b6153"}, + {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:95a5bad1ac8a5c77b4e658671642e4af3707f095d2b78a1fdd08af0dfb647624"}, + {file = "rpds_py-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3e53861b29a13d5b70116ea4230b5f0f3547b2c222c5daa090eb7c9c82d7f664"}, + {file = "rpds_py-0.21.0-cp310-none-win32.whl", hash = "sha256:ea3a6ac4d74820c98fcc9da4a57847ad2cc36475a8bd9683f32ab6d47a2bd682"}, + {file = "rpds_py-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:b8f107395f2f1d151181880b69a2869c69e87ec079c49c0016ab96860b6acbe5"}, + {file = "rpds_py-0.21.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5555db3e618a77034954b9dc547eae94166391a98eb867905ec8fcbce1308d95"}, + {file = "rpds_py-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97ef67d9bbc3e15584c2f3c74bcf064af36336c10d2e21a2131e123ce0f924c9"}, + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab2c2a26d2f69cdf833174f4d9d86118edc781ad9a8fa13970b527bf8236027"}, + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4e8921a259f54bfbc755c5bbd60c82bb2339ae0324163f32868f63f0ebb873d9"}, + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a7ff941004d74d55a47f916afc38494bd1cfd4b53c482b77c03147c91ac0ac3"}, + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5145282a7cd2ac16ea0dc46b82167754d5e103a05614b724457cffe614f25bd8"}, + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de609a6f1b682f70bb7163da745ee815d8f230d97276db049ab447767466a09d"}, + {file = "rpds_py-0.21.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40c91c6e34cf016fa8e6b59d75e3dbe354830777fcfd74c58b279dceb7975b75"}, + {file = "rpds_py-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d2132377f9deef0c4db89e65e8bb28644ff75a18df5293e132a8d67748397b9f"}, + {file = "rpds_py-0.21.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0a9e0759e7be10109645a9fddaaad0619d58c9bf30a3f248a2ea57a7c417173a"}, + {file = "rpds_py-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e20da3957bdf7824afdd4b6eeb29510e83e026473e04952dca565170cd1ecc8"}, + {file = "rpds_py-0.21.0-cp311-none-win32.whl", hash = "sha256:f71009b0d5e94c0e86533c0b27ed7cacc1239cb51c178fd239c3cfefefb0400a"}, + {file = "rpds_py-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:e168afe6bf6ab7ab46c8c375606298784ecbe3ba31c0980b7dcbb9631dcba97e"}, + {file = "rpds_py-0.21.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:30b912c965b2aa76ba5168fd610087bad7fcde47f0a8367ee8f1876086ee6d1d"}, + {file = "rpds_py-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ca9989d5d9b1b300bc18e1801c67b9f6d2c66b8fd9621b36072ed1df2c977f72"}, + {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f54e7106f0001244a5f4cf810ba8d3f9c542e2730821b16e969d6887b664266"}, + {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fed5dfefdf384d6fe975cc026886aece4f292feaf69d0eeb716cfd3c5a4dd8be"}, + {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:590ef88db231c9c1eece44dcfefd7515d8bf0d986d64d0caf06a81998a9e8cab"}, + {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f983e4c2f603c95dde63df633eec42955508eefd8d0f0e6d236d31a044c882d7"}, + {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b229ce052ddf1a01c67d68166c19cb004fb3612424921b81c46e7ea7ccf7c3bf"}, + {file = "rpds_py-0.21.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ebf64e281a06c904a7636781d2e973d1f0926a5b8b480ac658dc0f556e7779f4"}, + {file = "rpds_py-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:998a8080c4495e4f72132f3d66ff91f5997d799e86cec6ee05342f8f3cda7dca"}, + {file = "rpds_py-0.21.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:98486337f7b4f3c324ab402e83453e25bb844f44418c066623db88e4c56b7c7b"}, + {file = "rpds_py-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a78d8b634c9df7f8d175451cfeac3810a702ccb85f98ec95797fa98b942cea11"}, + {file = "rpds_py-0.21.0-cp312-none-win32.whl", hash = "sha256:a58ce66847711c4aa2ecfcfaff04cb0327f907fead8945ffc47d9407f41ff952"}, + {file = "rpds_py-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:e860f065cc4ea6f256d6f411aba4b1251255366e48e972f8a347cf88077b24fd"}, + {file = "rpds_py-0.21.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ee4eafd77cc98d355a0d02f263efc0d3ae3ce4a7c24740010a8b4012bbb24937"}, + {file = "rpds_py-0.21.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:688c93b77e468d72579351a84b95f976bd7b3e84aa6686be6497045ba84be560"}, + {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c38dbf31c57032667dd5a2f0568ccde66e868e8f78d5a0d27dcc56d70f3fcd3b"}, + {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2d6129137f43f7fa02d41542ffff4871d4aefa724a5fe38e2c31a4e0fd343fb0"}, + {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:520ed8b99b0bf86a176271f6fe23024323862ac674b1ce5b02a72bfeff3fff44"}, + {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaeb25ccfb9b9014a10eaf70904ebf3f79faaa8e60e99e19eef9f478651b9b74"}, + {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af04ac89c738e0f0f1b913918024c3eab6e3ace989518ea838807177d38a2e94"}, + {file = "rpds_py-0.21.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9b76e2afd585803c53c5b29e992ecd183f68285b62fe2668383a18e74abe7a3"}, + {file = "rpds_py-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5afb5efde74c54724e1a01118c6e5c15e54e642c42a1ba588ab1f03544ac8c7a"}, + {file = "rpds_py-0.21.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:52c041802a6efa625ea18027a0723676a778869481d16803481ef6cc02ea8cb3"}, + {file = "rpds_py-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ee1e4fc267b437bb89990b2f2abf6c25765b89b72dd4a11e21934df449e0c976"}, + {file = "rpds_py-0.21.0-cp313-none-win32.whl", hash = "sha256:0c025820b78817db6a76413fff6866790786c38f95ea3f3d3c93dbb73b632202"}, + {file = "rpds_py-0.21.0-cp313-none-win_amd64.whl", hash = "sha256:320c808df533695326610a1b6a0a6e98f033e49de55d7dc36a13c8a30cfa756e"}, + {file = "rpds_py-0.21.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:2c51d99c30091f72a3c5d126fad26236c3f75716b8b5e5cf8effb18889ced928"}, + {file = "rpds_py-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbd7504a10b0955ea287114f003b7ad62330c9e65ba012c6223dba646f6ffd05"}, + {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6dcc4949be728ede49e6244eabd04064336012b37f5c2200e8ec8eb2988b209c"}, + {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f414da5c51bf350e4b7960644617c130140423882305f7574b6cf65a3081cecb"}, + {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9afe42102b40007f588666bc7de82451e10c6788f6f70984629db193849dced1"}, + {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b929c2bb6e29ab31f12a1117c39f7e6d6450419ab7464a4ea9b0b417174f044"}, + {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8404b3717da03cbf773a1d275d01fec84ea007754ed380f63dfc24fb76ce4592"}, + {file = "rpds_py-0.21.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e12bb09678f38b7597b8346983d2323a6482dcd59e423d9448108c1be37cac9d"}, + {file = "rpds_py-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58a0e345be4b18e6b8501d3b0aa540dad90caeed814c515e5206bb2ec26736fd"}, + {file = "rpds_py-0.21.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c3761f62fcfccf0864cc4665b6e7c3f0c626f0380b41b8bd1ce322103fa3ef87"}, + {file = "rpds_py-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c2b2f71c6ad6c2e4fc9ed9401080badd1469fa9889657ec3abea42a3d6b2e1ed"}, + {file = "rpds_py-0.21.0-cp39-none-win32.whl", hash = "sha256:b21747f79f360e790525e6f6438c7569ddbfb1b3197b9e65043f25c3c9b489d8"}, + {file = "rpds_py-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:0626238a43152918f9e72ede9a3b6ccc9e299adc8ade0d67c5e142d564c9a83d"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6b4ef7725386dc0762857097f6b7266a6cdd62bfd209664da6712cb26acef035"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6bc0e697d4d79ab1aacbf20ee5f0df80359ecf55db33ff41481cf3e24f206919"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da52d62a96e61c1c444f3998c434e8b263c384f6d68aca8274d2e08d1906325c"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:98e4fe5db40db87ce1c65031463a760ec7906ab230ad2249b4572c2fc3ef1f9f"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30bdc973f10d28e0337f71d202ff29345320f8bc49a31c90e6c257e1ccef4333"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:faa5e8496c530f9c71f2b4e1c49758b06e5f4055e17144906245c99fa6d45356"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32eb88c30b6a4f0605508023b7141d043a79b14acb3b969aa0b4f99b25bc7d4a"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a89a8ce9e4e75aeb7fa5d8ad0f3fecdee813802592f4f46a15754dcb2fd6b061"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:241e6c125568493f553c3d0fdbb38c74babf54b45cef86439d4cd97ff8feb34d"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:3b766a9f57663396e4f34f5140b3595b233a7b146e94777b97a8413a1da1be18"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:af4a644bf890f56e41e74be7d34e9511e4954894d544ec6b8efe1e21a1a8da6c"}, + {file = "rpds_py-0.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3e30a69a706e8ea20444b98a49f386c17b26f860aa9245329bab0851ed100677"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:031819f906bb146561af051c7cef4ba2003d28cff07efacef59da973ff7969ba"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b876f2bc27ab5954e2fd88890c071bd0ed18b9c50f6ec3de3c50a5ece612f7a6"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc5695c321e518d9f03b7ea6abb5ea3af4567766f9852ad1560f501b17588c7b"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4de1da871b5c0fd5537b26a6fc6814c3cc05cabe0c941db6e9044ffbb12f04a"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:878f6fea96621fda5303a2867887686d7a198d9e0f8a40be100a63f5d60c88c9"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8eeec67590e94189f434c6d11c426892e396ae59e4801d17a93ac96b8c02a6c"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ff2eba7f6c0cb523d7e9cff0903f2fe1feff8f0b2ceb6bd71c0e20a4dcee271"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a429b99337062877d7875e4ff1a51fe788424d522bd64a8c0a20ef3021fdb6ed"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:d167e4dbbdac48bd58893c7e446684ad5d425b407f9336e04ab52e8b9194e2ed"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:4eb2de8a147ffe0626bfdc275fc6563aa7bf4b6db59cf0d44f0ccd6ca625a24e"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e78868e98f34f34a88e23ee9ccaeeec460e4eaf6db16d51d7a9b883e5e785a5e"}, + {file = "rpds_py-0.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4991ca61656e3160cdaca4851151fd3f4a92e9eba5c7a530ab030d6aee96ec89"}, + {file = "rpds_py-0.21.0.tar.gz", hash = "sha256:ed6378c9d66d0de903763e7706383d60c33829581f0adff47b6535f1802fa6db"}, +] + [[package]] name = "ruff" version = "0.7.4" @@ -677,6 +1106,18 @@ files = [ {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] +[[package]] +name = "tomlkit" +version = "0.13.2" +description = "Style preserving TOML library" +category = "dev" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, +] + [[package]] name = "types-protobuf" version = "5.28.3.20241030" @@ -801,4 +1242,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "b39a0619bd7665abf08c4cd29cb05f5c8af5af095e440d42518f2f302e4ab4a5" +content-hash = "2cb606755b48d1b5fc03f8c96825ee24848260ac5408014312eeb7c9b0db98b8" diff --git a/pyproject.toml b/pyproject.toml index d3536cc..eb490e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,9 +5,16 @@ description = "Generate Python MyPy stub modules from protobuf files." authors = ["zerlok "] readme = "README.md" license = "MIT" +keywords = [ + "python", + "codegen", + "protobuf", + "grpc", +] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", + "Operating System :: OS Independent", "Topic :: Software Development :: Code Generators", "Typing :: Typed", ] @@ -26,16 +33,17 @@ types-protobuf = "^5.28.3.20241030" mypy = "^1.13.0" pytest = "^8.3.3" pytest-cov = "^6.0.0" +pytest-mypy-plugins = "^3.1.2" ruff = "^0.7.4" grpc-stubs = "^1.53.0.5" -# TODO: specify pypi package version -brokrpc = { path = "../brokrpc", extras = ["aiormq"], develop = true, python = "^3.12" } +BrokRPC = { version = "^0.1.0", python = "^3.12" } [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" + [tool.ruff] include = ["src/**/*.py", "tests/**/*.py"] extend-exclude = ["tests/**/expected_gen/**.py"] @@ -57,16 +65,17 @@ ignore = [ "S101", # allow asserts for tests checks and mypy help ] + [tool.mypy] files = ["src", "tests"] strict = true - [[tool.mypy.overrides]] module = ["tests.integration.cases.*.expected_gen.*"] ignore_missing_imports = true ignore_errors = true + [tool.pytest.ini_options] pythonpath = [ "src", From 8939a1321e731acde4027a3f90e56a2f0da59f04 Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 01:44:06 +0100 Subject: [PATCH 5/9] add mypy test to brokrpc --- .../cases/case_000_greeting/test_mypy.yml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/integration/cases/case_000_greeting/test_mypy.yml diff --git a/tests/integration/cases/case_000_greeting/test_mypy.yml b/tests/integration/cases/case_000_greeting/test_mypy.yml new file mode 100644 index 0000000..4ec3440 --- /dev/null +++ b/tests/integration/cases/case_000_greeting/test_mypy.yml @@ -0,0 +1,22 @@ +- case: valid_server_and_client_types + env: + - MYPYPATH=tests/integration/cases/case_000_greeting/expected_gen/ + + main: |- + from brokrpc.rpc.client import Client + from greeting_brokrpc import GreeterService, create_client + + reveal_type(GreeterService) # N: Revealed type is "def () -> greeting_brokrpc.GreeterService" + + s: GreeterService + reveal_type(s.greet) # N: Revealed type is "def (request: brokrpc.message.Message[greeting_pb2.GreetRequest]) -> typing.Coroutine[Any, Any, greeting_pb2.GreetResponse]" + + async def main(client: Client) -> None: + async with create_client(client) as greeter_client: + reveal_type(greeter_client) # N: Revealed type is "greeting_brokrpc.GreeterClient" + reveal_type(greeter_client.greet) # N: Revealed type is "def (request: greeting_pb2.GreetRequest) -> typing.Coroutine[Any, Any, brokrpc.message.Message[greeting_pb2.GreetResponse]]" + + mypy_config: |- + [mypy-aiormq.*,pamqp.*] + ignore_missing_imports = True + ignore_errors = True From 78b53057a320354b5b26e55e316bc8bf0758e041 Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 01:52:01 +0100 Subject: [PATCH 6/9] fix typings for 3.9 --- poetry.lock | 2 +- pyproject.toml | 2 +- src/pyprotostuben/protobuf/visitor/walker.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 20dac6e..9a66532 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1242,4 +1242,4 @@ propcache = ">=0.2.0" [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "2cb606755b48d1b5fc03f8c96825ee24848260ac5408014312eeb7c9b0db98b8" +content-hash = "26d9cf8ff919f05e1afea21cd3c1c50ac7bb360783b903e7ab550972c35710a8" diff --git a/pyproject.toml b/pyproject.toml index eb490e5..4f81959 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ pytest-cov = "^6.0.0" pytest-mypy-plugins = "^3.1.2" ruff = "^0.7.4" grpc-stubs = "^1.53.0.5" -BrokRPC = { version = "^0.1.0", python = "^3.12" } +BrokRPC = { version = "^0.1.0", python = ">=3.12,<4.0" } [build-system] diff --git a/src/pyprotostuben/protobuf/visitor/walker.py b/src/pyprotostuben/protobuf/visitor/walker.py index 14f226d..1d44f25 100644 --- a/src/pyprotostuben/protobuf/visitor/walker.py +++ b/src/pyprotostuben/protobuf/visitor/walker.py @@ -166,7 +166,7 @@ def walk(self, meta: T_contra, *files: FileDescriptorProto) -> None: ) ) - def __walk_enums(self, context: BaseContext[T_contra, FileDescriptorProto | DescriptorProto]) -> None: + def __walk_enums(self, context: BaseContext[T_contra, t.Union[FileDescriptorProto, DescriptorProto]]) -> None: for i, enum_type in enumerate(context.item.enum_type): self.visit_enum_descriptor_proto( EnumDescriptorContext( @@ -254,7 +254,7 @@ def __walk_methods(self, context: BaseContext[T_contra, ServiceDescriptorProto]) ) ) - def __walk_extensions(self, context: BaseContext[T_contra, FileDescriptorProto | DescriptorProto]) -> None: + def __walk_extensions(self, context: BaseContext[T_contra, t.Union[FileDescriptorProto, DescriptorProto]]) -> None: for i, ext in enumerate(context.item.extension): self.visit_field_descriptor_proto( FieldDescriptorContext( From 62835a30c9ec99a69aee5909714012673905c778 Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 01:52:12 +0100 Subject: [PATCH 7/9] skip brokrpc mypy tests for python < 3.12 --- tests/integration/cases/case_000_greeting/test_mypy.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/cases/case_000_greeting/test_mypy.yml b/tests/integration/cases/case_000_greeting/test_mypy.yml index 4ec3440..fed018a 100644 --- a/tests/integration/cases/case_000_greeting/test_mypy.yml +++ b/tests/integration/cases/case_000_greeting/test_mypy.yml @@ -20,3 +20,6 @@ [mypy-aiormq.*,pamqp.*] ignore_missing_imports = True ignore_errors = True + + skip: |- + sys.version_info[:2] < (3, 12) From 499a76214714054a78a818ca44e0efc488e0c6c0 Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 01:56:03 +0100 Subject: [PATCH 8/9] remove last `|` to support python 3.9 --- .github/workflows/publish.yaml | 4 +++- .github/workflows/pull-request.yaml | 4 ++-- src/pyprotostuben/protobuf/context.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 12ddc6a..cc36a0e 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -11,7 +11,9 @@ jobs: id-token: write steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' - uses: abatilo/actions-poetry@v2 - name: Poetry build run: poetry build -n diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 6956f51..1412c4d 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.9", "3.10", "3.11", "3.12" ] + python-version: &python_versions [ "3.9", "3.10", "3.11", "3.12", "3.13" ] steps: - uses: actions/checkout@v4 - name: Install Python ${{ matrix.python-version }} @@ -47,7 +47,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] + python-version: *python_versions protoc-version: [ "26.1" ] buf-version: [ "1.31.0" ] steps: diff --git a/src/pyprotostuben/protobuf/context.py b/src/pyprotostuben/protobuf/context.py index ab8bb39..1883998 100644 --- a/src/pyprotostuben/protobuf/context.py +++ b/src/pyprotostuben/protobuf/context.py @@ -112,7 +112,7 @@ def __register_enum(self, context: EnumDescriptorContext[object]) -> None: self._log.info("registered", qualname=qualname, info=info) - def __register_message(self, context: FileDescriptorContext[object] | DescriptorContext[object]) -> None: + def __register_message(self, context: t.Union[FileDescriptorContext[object], DescriptorContext[object]]) -> None: qualname, module, ns = self.__build_type( root=context.root_context if isinstance(context, DescriptorContext) else context, context=context, From 055cf899cdb72abf14ee5cb6d75c6edd405d8e3b Mon Sep 17 00:00:00 2001 From: zerlok Date: Fri, 22 Nov 2024 01:57:18 +0100 Subject: [PATCH 9/9] remove yaml anchors from workflows --- .github/workflows/pull-request.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 1412c4d..ea748e0 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: &python_versions [ "3.9", "3.10", "3.11", "3.12", "3.13" ] + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] steps: - uses: actions/checkout@v4 - name: Install Python ${{ matrix.python-version }} @@ -47,7 +47,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: *python_versions + python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] protoc-version: [ "26.1" ] buf-version: [ "1.31.0" ] steps: