aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2024-10-02 15:07:20 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2024-10-02 15:17:02 +0300
commit91a4451afcbafd41dd6c49c0a7b6b1d701ab4c9c (patch)
tree675adb650d5d1f37f8cd415b39f69ea4660d7334
parent6c39e2242d0ff2aa6ea07080256c950fb9ef5ab3 (diff)
downloadydb-91a4451afcbafd41dd6c49c0a7b6b1d701ab4c9c.tar.gz
Update contrib/python/mypy-protobuf to 3.5.0
commit_hash:bfda51486cc75a7834db8b71f122c4f26dde8b37
-rw-r--r--contrib/python/mypy-protobuf/.dist-info/METADATA8
-rw-r--r--contrib/python/mypy-protobuf/README.md64
-rw-r--r--contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py30
-rw-r--r--contrib/python/mypy-protobuf/mypy_protobuf/main.py131
-rw-r--r--contrib/python/mypy-protobuf/ya.make2
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)