diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2024-10-02 15:07:20 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2024-10-02 15:17:02 +0300 |
commit | 91a4451afcbafd41dd6c49c0a7b6b1d701ab4c9c (patch) | |
tree | 675adb650d5d1f37f8cd415b39f69ea4660d7334 | |
parent | 6c39e2242d0ff2aa6ea07080256c950fb9ef5ab3 (diff) | |
download | ydb-91a4451afcbafd41dd6c49c0a7b6b1d701ab4c9c.tar.gz |
Update contrib/python/mypy-protobuf to 3.5.0
commit_hash:bfda51486cc75a7834db8b71f122c4f26dde8b37
-rw-r--r-- | contrib/python/mypy-protobuf/.dist-info/METADATA | 8 | ||||
-rw-r--r-- | contrib/python/mypy-protobuf/README.md | 64 | ||||
-rw-r--r-- | contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py | 30 | ||||
-rw-r--r-- | contrib/python/mypy-protobuf/mypy_protobuf/main.py | 131 | ||||
-rw-r--r-- | contrib/python/mypy-protobuf/ya.make | 2 |
5 files changed, 156 insertions, 79 deletions
diff --git a/contrib/python/mypy-protobuf/.dist-info/METADATA b/contrib/python/mypy-protobuf/.dist-info/METADATA index 2809f37c2a..934bb64a10 100644 --- a/contrib/python/mypy-protobuf/.dist-info/METADATA +++ b/contrib/python/mypy-protobuf/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: mypy-protobuf -Version: 3.3.0 +Version: 3.5.0 Summary: Generate mypy stub files from protobuf specs Home-page: https://github.com/nipunn1313/mypy-protobuf Download-URL: https://github.com/nipunn1313/mypy-protobuf/releases @@ -8,8 +8,8 @@ Author: Nipunn Koorapati Author-email: nipunn1313@gmail.com License: Apache License 2.0 Keywords: mypy proto dropbox -Requires-Python: >=3.7 +Requires-Python: >=3.8 License-File: LICENSE -Requires-Dist: protobuf (>=3.19.4) -Requires-Dist: types-protobuf (>=3.19.12) +Requires-Dist: protobuf (>=4.23.4) +Requires-Dist: types-protobuf (>=4.23.0.2) diff --git a/contrib/python/mypy-protobuf/README.md b/contrib/python/mypy-protobuf/README.md index ccdc5997e8..a1bfe29279 100644 --- a/contrib/python/mypy-protobuf/README.md +++ b/contrib/python/mypy-protobuf/README.md @@ -12,22 +12,28 @@ Built originally with love at [Dropbox](https://github.com/dropbox) See [Changelog](CHANGELOG.md) for recent changes. ## Requirements to run mypy-protobuf + Earlier releases might work, but aren't tested -- [protoc >= 3.19.4](https://github.com/protocolbuffers/protobuf/releases) -- [python-protobuf >= 3.19.4](https://pypi.org/project/protobuf/) - matching protoc release -- [python >= 3.7](https://www.python.org/downloads/source/) - for running mypy-protobuf plugin. + +- [protoc >= 23.4](https://github.com/protocolbuffers/protobuf/releases) +- [python-protobuf >= 4.23.4](https://pypi.org/project/protobuf/) - matching protoc release +- [python >= 3.8](https://www.python.org/downloads/source/) - for running mypy-protobuf plugin. ## Requirements to run typecheckers on stubs generated by mypy-protobuf + Earlier releases might work, but aren't tested -- [mypy >= v0.941](https://pypi.org/project/mypy) or [pyright >= 1.1.206](https://github.com/microsoft/pyright) -- [python-protobuf >= 3.19.4](https://pypi.org/project/protobuf/) - matching protoc release -- [types-protobuf >= 3.19.12](https://pypi.org/project/types-protobuf/) - for stubs from the google.protobuf library + +- [mypy >= v1.4.1](https://pypi.org/project/mypy) or [pyright >= 1.1.206](https://github.com/microsoft/pyright) +- [python-protobuf >= 4.23.4](https://pypi.org/project/protobuf/) - matching protoc release +- [types-protobuf >= 4.23.0.2](https://pypi.org/project/types-protobuf/) - for stubs from the google.protobuf library ### To run typecheckers on code generated with grpc plugin - you'll additionally need + Earlier releases might work, but aren't tested -- [grpcio>=1.47.0](https://pypi.org/project/grpcio/) -- [grpcio-tools>=1.47.0](https://pypi.org/project/grpcio-tools/) -- [grpc-stubs>=1.24.9](https://pypi.org/project/grpc-stubs/) + +- [grpcio>=1.56.2](https://pypi.org/project/grpcio/) +- [grpcio-tools>=1.56.2](https://pypi.org/project/grpcio-tools/) +- [grpc-stubs>=1.53.0.2](https://pypi.org/project/grpc-stubs/) Other configurations may work, but are not continuously tested currently. We would be open to expanding this list - file an issue on the issue tracker. @@ -35,10 +41,13 @@ We would be open to expanding this list - file an issue on the issue tracker. ## Installation The plugin can be installed with + ``` pip3 install mypy-protobuf ``` + To install unreleased + ``` REV=main # or whichever unreleased git rev you'd like pip3 install git+https://github.com/nipunn1313/mypy-protobuf.git@$REV @@ -48,6 +57,7 @@ pip3 install git+https://github.com/nipunn1313/mypy-protobuf.git@$REV#subdirecto ``` In order to run mypy on the generated code, you'll need to install + ``` pip3 install mypy>=0.910 types-protobuf>=0.1.14 ``` @@ -56,14 +66,19 @@ pip3 install mypy>=0.910 types-protobuf>=0.1.14 On posix, protoc-gen-mypy is installed to python's executable bin. Assuming that's on your $PATH, you can run + ``` protoc --python_out=output/location --mypy_out=output/location ``` + Alternately, you can explicitly provide the path: + ``` protoc --plugin=protoc-gen-mypy=path/to/protoc-gen-mypy --python_out=output/location --mypy_out=output/location ``` + Check the version number with + ``` > protoc-gen-mypy --version ``` @@ -85,18 +100,21 @@ will appear as docstrings in .pyi files. Useful in IDEs for showing completions ### Types enum int values more strongly Enum int values produce stubs which wrap the int values in NewType + ```proto enum MyEnum { HELLO = 0; WORLD = 1; } ``` + Will yield an [enum type wrapper](https://github.com/python/typeshed/blob/16ae4c61201cd8b96b8b22cdfb2ab9e89ba5bcf2/stubs/protobuf/google/protobuf/internal/enum_type_wrapper.pyi) whose methods type to `MyEnum.ValueType` (a `NewType(int)` rather than `int`. This allows mypy to catch bugs where the wrong enum value is being used. Calling code may be typed as follows. In python >= 3.7 + ```python # May need [PEP 563](https://www.python.org/dev/peps/pep-0563/) to postpone evaluation of annotations # from __future__ import annotations # Not needed with python>=3.11 or protobuf>=3.20.0 @@ -108,11 +126,13 @@ f(MyEnum.Value("HELLO")) With protobuf <= 3.20.0, for usages of cast, the type of `x` must be quoted After protobuf >= 3.20.0 - `ValueType` exists in the python code and quotes aren't needed until [upstream protobuf](https://github.com/protocolbuffers/protobuf/pull/8182) includes `ValueType` + ```python cast('MyEnum.ValueType', x) ``` Similarly, for type aliases with protobuf < 3.20.0, you must either quote the type or hide it behind `TYPE_CHECKING` + ```python from typing import Tuple, TYPE_CHECKING HELLO = Tuple['MyEnum.ValueType', 'MyEnum.ValueType'] @@ -122,7 +142,7 @@ if TYPE_CHECKING: #### Enum int impl details -mypy-protobuf autogenerates an instance of the EnumTypeWrapper as follows. +mypy-protobuf autogenerates an instance of the EnumTypeWrapper as follows. ```python class _MyEnum: @@ -141,14 +161,14 @@ WORLD: MyEnum.ValueType # 1 `_MyEnumEnumTypeWrapper` extends the EnumTypeWrapper to take/return MyEnum.ValueType rather than int `MyEnum` is an instance of the `EnumTypeWrapper`. + - Use `_MyEnum` and of metaclass is an implementation detail to make MyEnum.ValueType a valid type w/o a circular dependency - `V` is supported as an alias of `ValueType` for backward compatibility - - ### Supports generating type wrappers for fields and maps M.proto + ```proto message M { uint32 user_id = 1 [(mypy_protobuf.options).casttype="mymod.UserId"]; @@ -158,17 +178,21 @@ message M { ]; } ``` + mymod.py + ```python UserId = NewType("UserId", int) Email = NewType("Email", Text) ``` ### `py_generic_services` + If `py_generic_services` is set in your proto file, then mypy-protobuf will generate service stubs. If you want GRPC stubs instead - use the GRPC instructions. ### `readable_stubs` + If `readable_stubs` is set, mypy-protobuf will generate easier-to-read stubs. The downside to this approach - is that it's possible to generate stubs which do not pass mypy - particularly in the case of name collisions. mypy-protobuf defaults to generating stubs with fully qualified @@ -176,6 +200,7 @@ imports and mangled global-level identifiers to defend against name collisions b identifiers and field names. If you're ok with this risk, try it out! + ``` protoc --python_out=output/location --mypy_out=readable_stubs:output/location ``` @@ -195,7 +220,9 @@ protoc --python_out=output/location --mypy_out=relax_strict_optional_primitives: ``` ### Output suppression + To suppress output, you can run + ``` protoc --python_out=output/location --mypy_out=quiet:output/location ``` @@ -203,6 +230,7 @@ protoc --python_out=output/location --mypy_out=quiet:output/location ### GRPC This plugin provides stubs generation for grpcio generated code. + ``` protoc \ --python_out=output/location \ @@ -212,21 +240,23 @@ protoc \ ``` Note that generated code for grpc will work only together with code for python and locations should be the same. -If you need stubs for grpc internal code we suggest using this package https://github.com/shabbyrobe/grpc-stubs +If you need stubs for grpc internal code we suggest using this package https://github.com/shabbyrobe/grpc-stubs ### Targeting python2 support mypy-protobuf's drops support for targeting python2 with version 3.0. If you still need python2 support - + ``` python3 -m pip install mypy_protobuf==2.10 protoc --python_out=output/location --mypy_out=output/location mypy --target-version=2.7 {files} ``` - ## Contributing + Contributions to the implementation are welcome. Please run tests using `./run_test.sh`. Ensure code is formatted using black. + ``` pip3 install black black . @@ -271,9 +301,9 @@ black . - [@miaachan](https://github.com/miaachan) - [@Alphadelta14](https://github.com/Alphadelta14) - [@fergyfresh](https://github.com/fergyfresh) +- [@AlexWaygood](https://github.com/AlexWaygood) -Licence etc. ------------- +## Licence etc. 1. License: Apache 2.0. -2. Copyright attribution: Copyright (c) 2017 Dropbox, Inc. +2. Copyright attribution: Copyright (c) 2022 Nipunn Koorapati diff --git a/contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py b/contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py index 7b9f9a19eb..a638958a1b 100644 --- a/contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py +++ b/contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py @@ -4,9 +4,8 @@ """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -15,26 +14,11 @@ _sym_db = _symbol_database.Default() from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emypy_protobuf/extensions.proto\x12\rmypy_protobuf\x1a google/protobuf/descriptor.proto\"D\n\x0c\x46ieldOptions\x12\x10\n\x08\x63\x61sttype\x18\x01 \x01(\t\x12\x0f\n\x07keytype\x18\x02 \x01(\t\x12\x11\n\tvaluetype\x18\x03 \x01(\t:M\n\x07options\x12\x1d.google.protobuf.FieldOptions\x18\xe4\xd4\x03 \x01(\x0b\x32\x1b.mypy_protobuf.FieldOptions:5\n\x08\x63\x61sttype\x12\x1d.google.protobuf.FieldOptions\x18\xe0\xd4\x03 \x01(\tB\x02\x18\x01:4\n\x07keytype\x12\x1d.google.protobuf.FieldOptions\x18\xe2\xd4\x03 \x01(\tB\x02\x18\x01:6\n\tvaluetype\x12\x1d.google.protobuf.FieldOptions\x18\xe3\xd4\x03 \x01(\tB\x02\x18\x01\x62\x06proto3') - - -OPTIONS_FIELD_NUMBER = 60004 -options = DESCRIPTOR.extensions_by_name['options'] -CASTTYPE_FIELD_NUMBER = 60000 -casttype = DESCRIPTOR.extensions_by_name['casttype'] -KEYTYPE_FIELD_NUMBER = 60002 -keytype = DESCRIPTOR.extensions_by_name['keytype'] -VALUETYPE_FIELD_NUMBER = 60003 -valuetype = DESCRIPTOR.extensions_by_name['valuetype'] - -_FIELDOPTIONS = DESCRIPTOR.message_types_by_name['FieldOptions'] -FieldOptions = _reflection.GeneratedProtocolMessageType('FieldOptions', (_message.Message,), { - 'DESCRIPTOR' : _FIELDOPTIONS, - '__module__' : 'mypy_protobuf.extensions_pb2' - # @@protoc_insertion_point(class_scope:mypy_protobuf.FieldOptions) - }) -_sym_db.RegisterMessage(FieldOptions) +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emypy_protobuf/extensions.proto\x12\rmypy_protobuf\x1a google/protobuf/descriptor.proto\"D\n\x0c\x46ieldOptions\x12\x10\n\x08\x63\x61sttype\x18\x01 \x01(\t\x12\x0f\n\x07keytype\x18\x02 \x01(\t\x12\x11\n\tvaluetype\x18\x03 \x01(\t:L\n\x07options\x12\x1d.google.protobuf.FieldOptions\x18\x82\t \x01(\x0b\x32\x1b.mypy_protobuf.FieldOptions:4\n\x08\x63\x61sttype\x12\x1d.google.protobuf.FieldOptions\x18\xff\x08 \x01(\tB\x02\x18\x01:3\n\x07keytype\x12\x1d.google.protobuf.FieldOptions\x18\x80\t \x01(\tB\x02\x18\x01:5\n\tvaluetype\x12\x1d.google.protobuf.FieldOptions\x18\x81\t \x01(\tB\x02\x18\x01\x62\x06proto3') +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'mypy_protobuf.extensions_pb2', _globals) if _descriptor._USE_C_DESCRIPTORS == False: google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(options) google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(casttype) @@ -48,6 +32,6 @@ if _descriptor._USE_C_DESCRIPTORS == False: keytype._serialized_options = b'\030\001' valuetype._options = None valuetype._serialized_options = b'\030\001' - _FIELDOPTIONS._serialized_start=83 - _FIELDOPTIONS._serialized_end=151 + _globals['_FIELDOPTIONS']._serialized_start=83 + _globals['_FIELDOPTIONS']._serialized_end=151 # @@protoc_insertion_point(module_scope) diff --git a/contrib/python/mypy-protobuf/mypy_protobuf/main.py b/contrib/python/mypy-protobuf/mypy_protobuf/main.py index ea4635cb44..f0b3dbc7e8 100644 --- a/contrib/python/mypy-protobuf/mypy_protobuf/main.py +++ b/contrib/python/mypy-protobuf/mypy_protobuf/main.py @@ -24,7 +24,7 @@ from google.protobuf.internal.containers import RepeatedCompositeFieldContainer from google.protobuf.internal.well_known_types import WKTBASES from . import extensions_pb2 -__version__ = "3.3.0" +__version__ = "3.5.0" # SourceCodeLocation is defined by `message Location` here # https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto @@ -171,6 +171,7 @@ class PkgWriter(object): stabilization = { "Literal": (3, 8), "TypeAlias": (3, 10), + "final": (3, 8), } assert name in stabilization if not self.typing_extensions_min or self.typing_extensions_min < stabilization[name]: @@ -345,7 +346,7 @@ class PkgWriter(object): wl("V: {} = ValueType", self._import("typing_extensions", "TypeAlias")) wl("") wl( - "class {}({}[{}], {}): # noqa: F821", + "class {}({}[{}], {}):", etw_helper_class, self._import("google.protobuf.internal.enum_type_wrapper", "_EnumTypeWrapper"), value_type_helper_fq, @@ -406,6 +407,7 @@ class PkgWriter(object): class_name = desc.name if desc.name not in PYTHON_RESERVED else "_r_" + desc.name message_class = self._import("google.protobuf.message", "Message") + wl("@{}", self._import("typing_extensions", "final")) wl(f"class {class_name}({message_class}{addl_base}):") with self._indent(): scl = scl_prefix + [i] @@ -457,8 +459,7 @@ class PkgWriter(object): wl("def __init__(") with self._indent(): if any(f.name == "self" for f in desc.field): - wl("# pyright: reportSelfClsParameterName=false") - wl("self_,") + wl("self_, # pyright: ignore[reportSelfClsParameterName]") else: wl("self,") with self._indent(): @@ -574,7 +575,7 @@ class PkgWriter(object): wl("@{}", self._import("abc", "abstractmethod")) wl(f"def {method.name}(") with self._indent(): - wl(f"inst: {class_name},") + wl(f"inst: {class_name}, # pyright: ignore[reportSelfClsParameterName]") wl( "rpc_controller: {},", self._import("google.protobuf.service", "RpcController"), @@ -660,30 +661,77 @@ class PkgWriter(object): return ktype, vtype - def _callable_type(self, method: d.MethodDescriptorProto) -> str: + def _callable_type(self, method: d.MethodDescriptorProto, is_async: bool = False) -> str: + module = "grpc.aio" if is_async else "grpc" if method.client_streaming: if method.server_streaming: - return self._import("grpc", "StreamStreamMultiCallable") + return self._import(module, "StreamStreamMultiCallable") else: - return self._import("grpc", "StreamUnaryMultiCallable") + return self._import(module, "StreamUnaryMultiCallable") else: if method.server_streaming: - return self._import("grpc", "UnaryStreamMultiCallable") + return self._import(module, "UnaryStreamMultiCallable") else: - return self._import("grpc", "UnaryUnaryMultiCallable") + return self._import(module, "UnaryUnaryMultiCallable") - def _input_type(self, method: d.MethodDescriptorProto, use_stream_iterator: bool = True) -> str: + def _input_type(self, method: d.MethodDescriptorProto) -> str: result = self._import_message(method.input_type) - if use_stream_iterator and method.client_streaming: - result = f"{self._import('collections.abc', 'Iterator')}[{result}]" return result - def _output_type(self, method: d.MethodDescriptorProto, use_stream_iterator: bool = True) -> str: + def _servicer_input_type(self, method: d.MethodDescriptorProto) -> str: + result = self._import_message(method.input_type) + if method.client_streaming: + # See write_grpc_async_hacks(). + result = f"_MaybeAsyncIterator[{result}]" + return result + + def _output_type(self, method: d.MethodDescriptorProto) -> str: result = self._import_message(method.output_type) - if use_stream_iterator and method.server_streaming: - result = f"{self._import('collections.abc', 'Iterator')}[{result}]" return result + def _servicer_output_type(self, method: d.MethodDescriptorProto) -> str: + result = self._import_message(method.output_type) + if method.server_streaming: + # Union[Iterator[Resp], AsyncIterator[Resp]] is subtyped by Iterator[Resp] and AsyncIterator[Resp]. + # So both can be used in the covariant function return position. + iterator = f"{self._import('collections.abc', 'Iterator')}[{result}]" + aiterator = f"{self._import('collections.abc', 'AsyncIterator')}[{result}]" + result = f"{self._import('typing', 'Union')}[{iterator}, {aiterator}]" + else: + # Union[Resp, Awaitable[Resp]] is subtyped by Resp and Awaitable[Resp]. + # So both can be used in the covariant function return position. + # Awaitable[Resp] is equivalent to async def. + awaitable = f"{self._import('collections.abc', 'Awaitable')}[{result}]" + result = f"{self._import('typing', 'Union')}[{result}, {awaitable}]" + return result + + def write_grpc_async_hacks(self) -> None: + wl = self._write_line + # _MaybeAsyncIterator[Req] is supertyped by Iterator[Req] and AsyncIterator[Req]. + # So both can be used in the contravariant function parameter position. + wl("_T = {}('_T')", self._import("typing", "TypeVar")) + wl("") + wl( + "class _MaybeAsyncIterator({}[_T], {}[_T], metaclass={}):", + self._import("collections.abc", "AsyncIterator"), + self._import("collections.abc", "Iterator"), + self._import("abc", "ABCMeta"), + ) + with self._indent(): + wl("...") + wl("") + + # _ServicerContext is supertyped by grpc.ServicerContext and grpc.aio.ServicerContext + # So both can be used in the contravariant function parameter position. + wl( + "class _ServicerContext({}, {}): # type: ignore", + self._import("grpc", "ServicerContext"), + self._import("grpc.aio", "ServicerContext"), + ) + with self._indent(): + wl("...") + wl("") + def write_grpc_methods(self, service: d.ServiceDescriptorProto, scl_prefix: SourceCodeLocation) -> None: wl = self._write_line methods = [(i, m) for i, m in enumerate(service.method) if m.name not in PYTHON_RESERVED] @@ -698,20 +746,20 @@ class PkgWriter(object): with self._indent(): wl("self,") input_name = "request_iterator" if method.client_streaming else "request" - input_type = self._input_type(method) + input_type = self._servicer_input_type(method) wl(f"{input_name}: {input_type},") - wl("context: {},", self._import("grpc", "ServicerContext")) + wl("context: _ServicerContext,") wl( ") -> {}:{}", - self._output_type(method), + self._servicer_output_type(method), " ..." if not self._has_comments(scl) else "", - ), + ) if self._has_comments(scl): with self._indent(): if not self._write_comments(scl): wl("...") - def write_grpc_stub_methods(self, service: d.ServiceDescriptorProto, scl_prefix: SourceCodeLocation) -> None: + def write_grpc_stub_methods(self, service: d.ServiceDescriptorProto, scl_prefix: SourceCodeLocation, is_async: bool = False) -> None: wl = self._write_line methods = [(i, m) for i, m in enumerate(service.method) if m.name not in PYTHON_RESERVED] if not methods: @@ -720,10 +768,10 @@ class PkgWriter(object): for i, method in methods: scl = scl_prefix + [d.ServiceDescriptorProto.METHOD_FIELD_NUMBER, i] - wl("{}: {}[", method.name, self._callable_type(method)) + wl("{}: {}[", method.name, self._callable_type(method, is_async=is_async)) with self._indent(): - wl("{},", self._input_type(method, False)) - wl("{},", self._output_type(method, False)) + wl("{},", self._input_type(method)) + wl("{},", self._output_type(method)) wl("]") self._write_comments(scl) @@ -740,17 +788,31 @@ class PkgWriter(object): scl = scl_prefix + [i] # The stub client - wl(f"class {service.name}Stub:") + wl( + "class {}Stub:", + service.name, + ) with self._indent(): if self._write_comments(scl): wl("") - wl( - "def __init__(self, channel: {}) -> None: ...", - self._import("grpc", "Channel"), - ) + # To support casting into FooAsyncStub, allow both Channel and aio.Channel here. + channel = f"{self._import('typing', 'Union')}[{self._import('grpc', 'Channel')}, {self._import('grpc.aio', 'Channel')}]" + wl("def __init__(self, channel: {}) -> None: ...", channel) self.write_grpc_stub_methods(service, scl) wl("") + # The (fake) async stub client + wl( + "class {}AsyncStub:", + service.name, + ) + with self._indent(): + if self._write_comments(scl): + wl("") + # No __init__ since this isn't a real class (yet), and requires manual casting to work. + self.write_grpc_stub_methods(service, scl, is_async=True) + wl("") + # The service definition interface wl( "class {}Servicer(metaclass={}):", @@ -762,11 +824,13 @@ class PkgWriter(object): wl("") self.write_grpc_methods(service, scl) wl("") + server = self._import("grpc", "Server") + aserver = self._import("grpc.aio", "Server") wl( "def add_{}Servicer_to_server(servicer: {}Servicer, server: {}) -> None: ...", service.name, service.name, - self._import("grpc", "Server"), + f"{self._import('typing', 'Union')}[{server}, {aserver}]", ) wl("") @@ -889,7 +953,7 @@ class PkgWriter(object): for pkg, items in sorted(self.from_imports.items()): self._write_line(f"from {pkg} import (") - for (name, reexport_name) in sorted(items): + for name, reexport_name in sorted(items): if reexport_name is None: self._write_line(f" {name},") else: @@ -955,6 +1019,7 @@ def generate_mypy_grpc_stubs( relax_strict_optional_primitives, grpc=True, ) + pkg_writer.write_grpc_async_hacks() pkg_writer.write_grpc_services(fd.service, [d.FileDescriptorProto.SERVICE_FIELD_NUMBER]) assert name == fd.name @@ -965,9 +1030,7 @@ def generate_mypy_grpc_stubs( @contextmanager -def code_generation() -> Iterator[ - Tuple[plugin_pb2.CodeGeneratorRequest, plugin_pb2.CodeGeneratorResponse], -]: +def code_generation() -> Iterator[Tuple[plugin_pb2.CodeGeneratorRequest, plugin_pb2.CodeGeneratorResponse],]: if len(sys.argv) > 1 and sys.argv[1] in ("-V", "--version"): print("mypy-protobuf " + __version__) sys.exit(0) diff --git a/contrib/python/mypy-protobuf/ya.make b/contrib/python/mypy-protobuf/ya.make index 8249a60380..6ac24b9c93 100644 --- a/contrib/python/mypy-protobuf/ya.make +++ b/contrib/python/mypy-protobuf/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(3.3.0) +VERSION(3.5.0) LICENSE(Apache-2.0) |