Browse Source

intermediate changes
ref:194371cd7882ab34e84937b696b9da60df296d31

arcadia-devtools 2 years ago
parent
commit
847cacb2b6

+ 3 - 3
contrib/python/mypy-protobuf/.dist-info/METADATA

@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: mypy-protobuf
-Version: 2.10
+Version: 3.2.0
 Summary: Generate mypy stub files from protobuf specs
 Home-page: https://github.com/dropbox/mypy-protobuf
 Author: Nipunn Koorapati
@@ -11,8 +11,8 @@ Keywords: mypy proto dropbox
 Platform: UNKNOWN
 Requires-Python: >=3.6
 License-File: LICENSE
-Requires-Dist: protobuf (>=3.17.3)
-Requires-Dist: types-protobuf (>=3.17.4)
+Requires-Dist: protobuf (>=3.19.3)
+Requires-Dist: types-protobuf (>=3.19.5)
 
 UNKNOWN
 

+ 72 - 54
contrib/python/mypy-protobuf/README.md

@@ -5,27 +5,31 @@ mypy-protobuf: Generate mypy stub files from protobuf specs
 [![license](https://img.shields.io/github/license/dropbox/mypy-protobuf)](https://github.com/dropbox/mypy-protobuf/blob/main/LICENSE)
 ===========================================================
 
-2.10 will be the last version of mypy-protobuf which supports targeting python 2.7. Next will be
-mypy-protobuf 3.0 which will auspiciously only support targeting python3
+Starting in mypy-protobuf 3.0.0, only python3 targeting is supported
+2.10 is the last version of mypy-protobuf which supports targeting python 2.7.
 
 See [Changelog](CHANGELOG.md) for recent changes.
 
 ## Requirements to run mypy-protobuf
-[protoc >= 3.17.3](https://github.com/protocolbuffers/protobuf/releases)
-[python-protobuf >= 3.17.3](https://pypi.org/project/protobuf/) - matching protoc release
-[python >= 3.6](https://www.python.org/downloads/source/) - for running mypy-protobuf plugin.
-
-## Requirements to run mypy on stubs generated by mypy-protobuf
-[mypy >= v0.910](https://pypi.org/project/mypy)
-[python-protobuf >= 3.17.3](https://pypi.org/project/protobuf/) - matching protoc release
-[types-protobuf==3.17.3](https://pypi.org/project/types-protobuf/) - for stubs from the google.protobuf library
-
-### To run mypy on code generated with grpc plugin - you'll additionally need
-[grpcio>=1.38.1](https://pypi.org/project/grpcio/)
-[grpcio-tools>=1.38.1](https://pypi.org/project/grpcio-tools/)
-[grpc-stubs>=1.24.6](https://pypi.org/project/grpc-stubs/)
-
-Other configurations may work, but are not supported in testing currently. We would be open to expanding this list if a need arises - file an issue on the issue tracker.
+Earlier releases might work, but aren't tested
+- [protoc >= 3.19.3](https://github.com/protocolbuffers/protobuf/releases)
+- [python-protobuf >= 3.19.3](https://pypi.org/project/protobuf/) - matching protoc release
+- [python >= 3.7](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.931](https://pypi.org/project/mypy) or [pyright >= 1.1.206](https://github.com/microsoft/pyright)
+- [python-protobuf >= 3.19.3](https://pypi.org/project/protobuf/) - matching protoc release
+- [types-protobuf >= 3.19.5](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.40.0](https://pypi.org/project/grpcio/)
+- [grpcio-tools>=1.40.0](https://pypi.org/project/grpcio-tools/)
+- [grpc-stubs>=1.24.7](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.
 
 ## Installation
 
@@ -63,10 +67,6 @@ Check the version number with
 > protoc-gen-mypy --version
 ```
 
-## Getting Help
-
-Find other developers in the mypy-protobuf slack workspace ([Invitation Link](https://join.slack.com/t/mypy-protobuf/shared_invite/zt-scogn8b5-MhetFnFYGi6V513aRsbe_Q)). If your company uses slack and mypy-protobuf, you may opt to use slack-connect to make a shared channel.
-
 ## Implementation
 
 The implementation of the plugin is in `mypy_protobuf/main.py`, which installs to
@@ -84,57 +84,73 @@ 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 {
-  FOO = 0;
-  BAR = 1;
+  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.V` rather than `int`.
+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.
 
-mypy-protobuf  autogenerates an instance of the EnumTypeWrapper as follows.
+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.10 or protobuf>=3.20.0
+def f(x: MyEnum.ValueType):
+    print(x)
+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']
+if TYPE_CHECKING:
+    HELLO = Tuple[MyEnum.ValueType, MyEnum.ValueType]
+```
+
+#### Enum int impl details
+
+mypy-protobuf  autogenerates an instance of the EnumTypeWrapper as follows.
+
+```python
+class _MyEnum:
+    ValueType = typing.NewType('ValueType', builtins.int)
+    V: typing_extensions.TypeAlias = ValueType
+class _MyEnumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_MyEnum.ValueType], builtins.type):
+    DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
+    HELLO: _MyEnum.ValueType  # 0
+    WORLD: _MyEnum.ValueType  # 1
 class MyEnum(_MyEnum, metaclass=_MyEnumEnumTypeWrapper):
     pass
-class _MyEnum:
-    V = typing.NewType('V', builtins.int)
-class _MyEnumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_MyEnum.V], builtins.type):
-    DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor = ...
-    FOO = MyEnum.V(0)
-    BAR = MyEnum.V(1)
-FOO = MyEnum.V(0)
-BAR = MyEnum.V(1)
+
+HELLO: MyEnum.ValueType  # 0
+WORLD: MyEnum.ValueType  # 1
 ```
 
-`_MyEnumEnumTypeWrapper` extends the EnumTypeWrapper to take/return MyEnum.V rather than int
+`_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.V a valid type w/o a circular dependency
+- 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
 
-Calling code may be typed as follows.
 
-In python >= 3.7
-```
-# 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.10
-def f(x: MyEnum.V):
-    print(x)
-f(MyEnum.Value("FOO"))
-```
-
-Note that for usages of cast, the type of `x` must be quoted
-until [upstream protobuf](https://github.com/protocolbuffers/protobuf/pull/8182) includes `V`
-```
-cast('MyEnum.V', x)
-```
 
 ### Supports generating type wrappers for fields and maps
 
 M.proto
-```
+```proto
 message M {
-  uint32 user_id = 1 [(mypy_protobuf.casttype)="mymod.UserId"
+  uint32 user_id = 1 [(mypy_protobuf.casttype)="mymod.UserId"];
   map<uint32, string> email_by_uid = 2 [
     (mypy_protobuf.keytype)="path/to/mymod.UserId",
     (mypy_protobuf.valuetype)="path/to/mymod.Email"
@@ -142,7 +158,7 @@ message M {
 }
 ```
 mymod.py
-```
+```python
 UserId = NewType("UserId", int)
 Email = NewType("Email", Text)
 ```
@@ -252,6 +268,8 @@ black .
 - [@nelfin](https://github.com/nelfin)
 - [@alkasm](https://github.com/alkasm)
 - [@tarmath](https://github.com/tarmath)
+- [@jaredkhan](https://github.com/jaredkhan)
+- [@sodul](https://github.com/sodul)
 
 Licence etc.
 ------------

+ 11 - 39
contrib/python/mypy-protobuf/mypy_protobuf/extensions_pb2.py

@@ -3,6 +3,7 @@
 # source: mypy_protobuf/extensions.proto
 """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
@@ -14,49 +15,20 @@ _sym_db = _symbol_database.Default()
 from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
 
 
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='mypy_protobuf/extensions.proto',
-  package='mypy_protobuf',
-  syntax='proto2',
-  serialized_options=None,
-  create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\x1emypy_protobuf/extensions.proto\x12\rmypy_protobuf\x1a google/protobuf/descriptor.proto:1\n\x08\x63\x61sttype\x12\x1d.google.protobuf.FieldOptions\x18\xe0\xd4\x03 \x01(\t:0\n\x07keytype\x12\x1d.google.protobuf.FieldOptions\x18\xe2\xd4\x03 \x01(\t:2\n\tvaluetype\x12\x1d.google.protobuf.FieldOptions\x18\xe3\xd4\x03 \x01(\t'
-  ,
-  dependencies=[google_dot_protobuf_dot_descriptor__pb2.DESCRIPTOR,])
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emypy_protobuf/extensions.proto\x12\rmypy_protobuf\x1a google/protobuf/descriptor.proto:1\n\x08\x63\x61sttype\x12\x1d.google.protobuf.FieldOptions\x18\xe0\xd4\x03 \x01(\t:0\n\x07keytype\x12\x1d.google.protobuf.FieldOptions\x18\xe2\xd4\x03 \x01(\t:2\n\tvaluetype\x12\x1d.google.protobuf.FieldOptions\x18\xe3\xd4\x03 \x01(\t')
 
 
 CASTTYPE_FIELD_NUMBER = 60000
-casttype = _descriptor.FieldDescriptor(
-  name='casttype', full_name='mypy_protobuf.casttype', index=0,
-  number=60000, type=9, cpp_type=9, label=1,
-  has_default_value=False, default_value=b"".decode('utf-8'),
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key)
+casttype = DESCRIPTOR.extensions_by_name['casttype']
 KEYTYPE_FIELD_NUMBER = 60002
-keytype = _descriptor.FieldDescriptor(
-  name='keytype', full_name='mypy_protobuf.keytype', index=1,
-  number=60002, type=9, cpp_type=9, label=1,
-  has_default_value=False, default_value=b"".decode('utf-8'),
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key)
+keytype = DESCRIPTOR.extensions_by_name['keytype']
 VALUETYPE_FIELD_NUMBER = 60003
-valuetype = _descriptor.FieldDescriptor(
-  name='valuetype', full_name='mypy_protobuf.valuetype', index=2,
-  number=60003, type=9, cpp_type=9, label=1,
-  has_default_value=False, default_value=b"".decode('utf-8'),
-  message_type=None, enum_type=None, containing_type=None,
-  is_extension=True, extension_scope=None,
-  serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key)
-
-DESCRIPTOR.extensions_by_name['casttype'] = casttype
-DESCRIPTOR.extensions_by_name['keytype'] = keytype
-DESCRIPTOR.extensions_by_name['valuetype'] = valuetype
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(casttype)
-google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(keytype)
-google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(valuetype)
+valuetype = DESCRIPTOR.extensions_by_name['valuetype']
 
+if _descriptor._USE_C_DESCRIPTORS == False:
+  google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(casttype)
+  google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(keytype)
+  google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(valuetype)
+
+  DESCRIPTOR._options = None
 # @@protoc_insertion_point(module_scope)

+ 113 - 104
contrib/python/mypy-protobuf/mypy_protobuf/main.py

@@ -25,7 +25,7 @@ from google.protobuf.internal.containers import RepeatedCompositeFieldContainer
 from google.protobuf.internal.well_known_types import WKTBASES
 from . import extensions_pb2
 
-__version__ = "2.10"
+__version__ = "3.2.0"
 
 # SourceCodeLocation is defined by `message Location` here
 # https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/descriptor.proto
@@ -33,13 +33,11 @@ SourceCodeLocation = List[int]
 
 # So phabricator doesn't think mypy_protobuf.py is generated
 GENERATED = "@ge" + "nerated"
-HEADER = """\"\"\"
-{} by mypy-protobuf.  Do not edit manually!
+HEADER = f"""\"\"\"
+{GENERATED} by mypy-protobuf.  Do not edit manually!
 isort:skip_file
 \"\"\"
-""".format(
-    GENERATED
-)
+"""
 
 # See https://github.com/dropbox/mypy-protobuf/issues/73 for details
 PYTHON_RESERVED = {
@@ -99,7 +97,7 @@ def _mangle_global_identifier(name: str) -> str:
     message or enum named `Name`, so mangle it with a global___ prefix for
     internal references. Note that this doesn't affect inner enums/messages
     because they get fuly qualified when referenced within a file"""
-    return "global___{}".format(name)
+    return f"global___{name}"
 
 
 class Descriptors(object):
@@ -118,7 +116,7 @@ class Descriptors(object):
         ) -> None:
             for enum in enums:
                 self.message_to_fd[prefix + enum.name] = _fd
-                self.message_to_fd[prefix + enum.name + ".V"] = _fd
+                self.message_to_fd[prefix + enum.name + ".ValueType"] = _fd
 
         def _add_messages(
             messages: "RepeatedCompositeFieldContainer[d.DescriptorProto]",
@@ -229,7 +227,8 @@ class PkgWriter(object):
         self.indent = self.indent[:-4]
 
     def _write_line(self, line: str, *args: Any) -> None:
-        line = line.format(*args)
+        if args:
+            line = line.format(*args)
         if line == "":
             self.lines.append(line)
         else:
@@ -239,8 +238,7 @@ class PkgWriter(object):
         if text_block == "":
             return []
         return [
-            "{}".format(l[1:] if l.startswith(" ") else l)
-            for l in text_block.rstrip().split("\n")
+            l[1:] if l.startswith(" ") else l for l in text_block.rstrip().split("\n")
         ]
 
     def _has_comments(self, scl: SourceCodeLocation) -> bool:
@@ -269,14 +267,26 @@ class PkgWriter(object):
         if sci_loc.trailing_comments is not None:
             lines.extend(self._break_text(sci_loc.trailing_comments))
 
+        lines = [
+            # Escape triple-quotes that would otherwise end the docstring early.
+            line.replace("\\", "\\\\").replace('"""', r"\"\"\"")
+            for line in lines
+        ]
         if len(lines) == 1:
-            self._write_line('"""{}"""', lines[0])
+            line = lines[0]
+            if line.endswith(('"', "\\")):
+                # Docstrings are terminated with triple-quotes, so if the documentation itself ends in a quote,
+                # insert some whitespace to separate it from the closing quotes.
+                # This is not necessary with multiline comments
+                # because in that case we always insert a newline before the trailing triple-quotes.
+                line = line + " "
+            self._write_line(f'"""{line}"""')
         else:
             for i, line in enumerate(lines):
                 if i == 0:
-                    self._write_line('"""{}', line)
+                    self._write_line(f'"""{line}')
                 else:
-                    self._write_line("{}", line)
+                    self._write_line(f"{line}")
             self._write_line('"""')
 
         return True
@@ -293,20 +303,15 @@ class PkgWriter(object):
 
             scl = scl_prefix + [i]
             self._write_line(
-                "{} = {}({})",
-                val.name,
-                value_type,
-                val.number,
+                f"{val.name}: {value_type}  # {val.number}",
             )
             if self._write_comments(scl):
                 self._write_line("")  # Extra newline to separate
 
     def write_module_attributes(self) -> None:
         l = self._write_line
-        l(
-            "DESCRIPTOR: {} = ...",
-            self._import("google.protobuf.descriptor", "FileDescriptor"),
-        )
+        fd_type = self._import("google.protobuf.descriptor", "FileDescriptor")
+        l(f"DESCRIPTOR: {fd_type}")
         l("")
 
     def write_enums(
@@ -320,48 +325,46 @@ class PkgWriter(object):
             class_name = (
                 enum.name if enum.name not in PYTHON_RESERVED else "_r_" + enum.name
             )
-            value_type_fq = prefix + class_name + ".V"
+            value_type_fq = prefix + class_name + ".ValueType"
+            enum_helper_class = "_" + enum.name
+            value_type_helper_fq = prefix + enum_helper_class + ".ValueType"
+            etw_helper_class = "_" + enum.name + "EnumTypeWrapper"
+            scl = scl_prefix + [i]
 
-            l(
-                "class {}({}, metaclass={}):",
-                class_name,
-                "_" + enum.name,
-                "_" + enum.name + "EnumTypeWrapper",
-            )
-            with self._indent():
-                scl = scl_prefix + [i]
-                self._write_comments(scl)
-                l("pass")
-            l("class {}:", "_" + enum.name)
+            l(f"class {enum_helper_class}:")
             with self._indent():
                 l(
-                    "V = {}('V', {})",
+                    "ValueType = {}('ValueType', {})",
                     self._import("typing", "NewType"),
                     self._builtin("int"),
                 )
+                # Alias to the classic shorter definition "V"
+                l("V: {} = ValueType", self._import("typing_extensions", "TypeAlias"))
             l(
                 "class {}({}[{}], {}):",
-                "_" + enum.name + "EnumTypeWrapper",
+                etw_helper_class,
                 self._import(
                     "google.protobuf.internal.enum_type_wrapper", "_EnumTypeWrapper"
                 ),
-                "_" + enum.name + ".V",
+                value_type_helper_fq,
                 self._builtin("type"),
             )
             with self._indent():
-                l(
-                    "DESCRIPTOR: {} = ...",
-                    self._import("google.protobuf.descriptor", "EnumDescriptor"),
-                )
+                ed = self._import("google.protobuf.descriptor", "EnumDescriptor")
+                l(f"DESCRIPTOR: {ed}")
                 self.write_enum_values(
                     [
                         (i, v)
                         for i, v in enumerate(enum.value)
                         if v.name not in PROTO_ENUM_RESERVED
                     ],
-                    value_type_fq,
+                    value_type_helper_fq,
                     scl + [d.EnumDescriptorProto.VALUE_FIELD_NUMBER],
                 )
+            l(f"class {class_name}({enum_helper_class}, metaclass={etw_helper_class}):")
+            with self._indent():
+                self._write_comments(scl)
+                l("pass")
             l("")
 
             self.write_enum_values(
@@ -370,7 +373,7 @@ class PkgWriter(object):
                 scl + [d.EnumDescriptorProto.VALUE_FIELD_NUMBER],
             )
             if prefix == "" and not self.readable_stubs:
-                l("{} = {}", _mangle_global_identifier(class_name), class_name)
+                l(f"{_mangle_global_identifier(class_name)} = {class_name}")
                 l("")
             l("")
 
@@ -388,7 +391,7 @@ class PkgWriter(object):
             # Reproduce some hardcoded logic from the protobuf implementation - where
             # some specific "well_known_types" generated protos to have additional
             # base classes
-            addl_base = u""
+            addl_base = ""
             if self.fd.package + "." + desc.name in WKTBASES:
                 # chop off the .proto - and import the well known type
                 # eg `from google.protobuf.duration import Duration`
@@ -402,15 +405,13 @@ class PkgWriter(object):
                 desc.name if desc.name not in PYTHON_RESERVED else "_r_" + desc.name
             )
             message_class = self._import("google.protobuf.message", "Message")
-            l("class {}({}{}):", class_name, message_class, addl_base)
+            l(f"class {class_name}({message_class}{addl_base}):")
             with self._indent():
                 scl = scl_prefix + [i]
                 self._write_comments(scl)
 
-                l(
-                    "DESCRIPTOR: {} = ...",
-                    self._import("google.protobuf.descriptor", "Descriptor"),
-                )
+                desc_type = self._import("google.protobuf.descriptor", "Descriptor")
+                l(f"DESCRIPTOR: {desc_type}")
 
                 # Nested enums/messages
                 self.write_enums(
@@ -426,18 +427,19 @@ class PkgWriter(object):
 
                 # integer constants  for field numbers
                 for f in desc.field:
-                    l("{}_FIELD_NUMBER: {}", f.name.upper(), self._builtin("int"))
+                    l(f"{f.name.upper()}_FIELD_NUMBER: {self._builtin('int')}")
 
                 for idx, field in enumerate(desc.field):
                     if field.name in PYTHON_RESERVED:
                         continue
+                    field_type = self.python_type(field)
 
                     if (
                         is_scalar(field)
                         and field.label != d.FieldDescriptorProto.LABEL_REPEATED
                     ):
                         # Scalar non repeated fields are r/w
-                        l("{}: {} = ...", field.name, self.python_type(field))
+                        l(f"{field.name}: {field_type}")
                         if self._write_comments(
                             scl + [d.DescriptorProto.FIELD_FIELD_NUMBER, idx]
                         ):
@@ -446,12 +448,8 @@ class PkgWriter(object):
                         # r/o Getters for non-scalar fields and scalar-repeated fields
                         scl_field = scl + [d.DescriptorProto.FIELD_FIELD_NUMBER, idx]
                         l("@property")
-                        l(
-                            "def {}(self) -> {}:{}",
-                            field.name,
-                            self.python_type(field),
-                            " ..." if not self._has_comments(scl_field) else "",
-                        )
+                        body = " ..." if not self._has_comments(scl_field) else ""
+                        l(f"def {field.name}(self) -> {field_type}:{body}")
                         if self._has_comments(scl_field):
                             with self._indent():
                                 self._write_comments(scl_field)
@@ -462,10 +460,11 @@ class PkgWriter(object):
                 )
 
                 # Constructor
-                self_arg = (
-                    "self_" if any(f.name == "self" for f in desc.field) else "self"
-                )
-                l("def __init__({},", self_arg)
+                if any(f.name == "self" for f in desc.field):
+                    l("# pyright: reportSelfClsParameterName=false")
+                    l(f"def __init__(self_,")
+                else:
+                    l(f"def __init__(self,")
                 with self._indent():
                     constructor_fields = [
                         f for f in desc.field if f.name not in PYTHON_RESERVED
@@ -475,36 +474,30 @@ class PkgWriter(object):
                         # See https://github.com/dropbox/mypy-protobuf/issues/71
                         l("*,")
                     for field in constructor_fields:
+                        field_type = self.python_type(field, generic_container=True)
                         if (
                             self.fd.syntax == "proto3"
                             and is_scalar(field)
                             and field.label != d.FieldDescriptorProto.LABEL_REPEATED
                             and not self.relax_strict_optional_primitives
+                            and not field.proto3_optional
                         ):
-                            l(
-                                "{} : {} = ...,",
-                                field.name,
-                                self.python_type(field, generic_container=True),
-                            )
+                            l(f"{field.name}: {field_type} = ...,")
                         else:
-                            l(
-                                "{} : {}[{}] = ...,",
-                                field.name,
-                                self._import("typing", "Optional"),
-                                self.python_type(field, generic_container=True),
-                            )
+                            opt = self._import("typing", "Optional")
+                            l(f"{field.name}: {opt}[{field_type}] = ...,")
                     l(") -> None: ...")
 
                 self.write_stringly_typed_fields(desc)
 
             if prefix == "" and not self.readable_stubs:
-                l("{} = {}", _mangle_global_identifier(class_name), class_name)
+                l(f"{_mangle_global_identifier(class_name)} = {class_name}")
             l("")
 
     def write_stringly_typed_fields(self, desc: d.DescriptorProto) -> None:
         """Type the stringly-typed methods as a Union[Literal, Literal ...]"""
         l = self._write_line
-        # HasField, ClearField, WhichOneof accepts both bytes/unicode
+        # HasField, ClearField, WhichOneof accepts both bytes/str
         # HasField only supports singular. ClearField supports repeated as well
         # In proto3, HasField only supports message fields and optional fields
         # HasField always supports oneof fields
@@ -534,12 +527,8 @@ class PkgWriter(object):
         hf_fields.extend(wo_fields.keys())
         cf_fields.extend(wo_fields.keys())
 
-        hf_fields_text = ",".join(
-            sorted('u"{}",b"{}"'.format(name, name) for name in hf_fields)
-        )
-        cf_fields_text = ",".join(
-            sorted('u"{}",b"{}"'.format(name, name) for name in cf_fields)
-        )
+        hf_fields_text = ",".join(sorted(f'"{name}",b"{name}"' for name in hf_fields))
+        cf_fields_text = ",".join(sorted(f'"{name}",b"{name}"' for name in cf_fields))
 
         if not hf_fields and not cf_fields and not wo_fields:
             return
@@ -564,12 +553,12 @@ class PkgWriter(object):
             l(
                 "def WhichOneof(self, oneof_group: {}[{}]) -> {}[{}[{}]]: ...",
                 self._import("typing_extensions", "Literal"),
-                # Accepts both unicode and bytes in both py2 and py3
-                'u"{}",b"{}"'.format(wo_field, wo_field),
+                # Accepts both str and bytes
+                f'"{wo_field}",b"{wo_field}"',
                 self._import("typing", "Optional"),
                 self._import("typing_extensions", "Literal"),
-                # Returns `str` in both py2 and py3 (bytes in py2, unicode in py3)
-                ",".join('"{}"'.format(m) for m in members),
+                # Returns `str`
+                ",".join(f'"{m}"' for m in members),
             )
 
     def write_extensions(
@@ -578,11 +567,15 @@ class PkgWriter(object):
         scl_prefix: SourceCodeLocation,
     ) -> None:
         l = self._write_line
+
+        for ext in extensions:
+            l(f"{ext.name.upper()}_FIELD_NUMBER: {self._builtin('int')}")
+
         for i, ext in enumerate(extensions):
             scl = scl_prefix + [i]
 
             l(
-                "{}: {}[{}, {}] = ...",
+                "{}: {}[{}, {}]",
                 ext.name,
                 self._import(
                     "google.protobuf.internal.extension_dict",
@@ -597,10 +590,15 @@ class PkgWriter(object):
     def write_methods(
         self,
         service: d.ServiceDescriptorProto,
+        class_name: str,
         is_abstract: bool,
         scl_prefix: SourceCodeLocation,
     ) -> None:
         l = self._write_line
+        l(
+            "DESCRIPTOR: {}",
+            self._import("google.protobuf.descriptor", "ServiceDescriptor"),
+        )
         methods = [
             (i, m)
             for i, m in enumerate(service.method)
@@ -611,18 +609,20 @@ class PkgWriter(object):
         for i, method in methods:
             if is_abstract:
                 l("@{}", self._import("abc", "abstractmethod"))
-            l("def {}(self,", method.name)
+            l(f"def {method.name}(")
             with self._indent():
+                l(f"inst: {class_name},")
                 l(
                     "rpc_controller: {},",
                     self._import("google.protobuf.service", "RpcController"),
                 )
                 l("request: {},", self._import_message(method.input_type))
                 l(
-                    "done: {}[{}[[{}], None]],",
+                    "callback: {}[{}[[{}], None]]{},",
                     self._import("typing", "Optional"),
                     self._import("typing", "Callable"),
                     self._import_message(method.output_type),
+                    "" if is_abstract else " = None",
                 )
 
             scl_method = scl_prefix + [d.ServiceDescriptorProto.METHOD_FIELD_NUMBER, i]
@@ -659,17 +659,22 @@ class PkgWriter(object):
             )
             with self._indent():
                 self._write_comments(scl)
-                self.write_methods(service, is_abstract=True, scl_prefix=scl)
+                self.write_methods(
+                    service, class_name, is_abstract=True, scl_prefix=scl
+                )
 
             # The stub client
-            l("class {}({}):", service.name + "_Stub", class_name)
+            stub_class_name = service.name + "_Stub"
+            l("class {}({}):", stub_class_name, class_name)
             with self._indent():
                 self._write_comments(scl)
                 l(
                     "def __init__(self, rpc_channel: {}) -> None: ...",
                     self._import("google.protobuf.service", "RpcChannel"),
                 )
-                self.write_methods(service, is_abstract=False, scl_prefix=scl)
+                self.write_methods(
+                    service, stub_class_name, is_abstract=False, scl_prefix=scl
+                )
 
     def _import_casttype(self, casttype: str) -> str:
         split = casttype.split(".")
@@ -716,7 +721,7 @@ class PkgWriter(object):
     ) -> str:
         result = self._import_message(method.input_type)
         if use_stream_iterator and method.client_streaming:
-            result = "{}[{}]".format(self._import("typing", "Iterator"), result)
+            result = f"{self._import('typing', 'Iterator')}[{result}]"
         return result
 
     def _output_type(
@@ -724,7 +729,7 @@ class PkgWriter(object):
     ) -> str:
         result = self._import_message(method.output_type)
         if use_stream_iterator and method.server_streaming:
-            result = "{}[{}]".format(self._import("typing", "Iterator"), result)
+            result = f"{self._import('typing', 'Iterator')}[{result}]"
         return result
 
     def write_grpc_methods(
@@ -745,7 +750,11 @@ class PkgWriter(object):
             l("@{}", self._import("abc", "abstractmethod"))
             l("def {}(self,", method.name)
             with self._indent():
-                l("request: {},", self._input_type(method))
+                input_name = (
+                    "request_iterator" if method.client_streaming else "request"
+                )
+                input_type = self._input_type(method)
+                l(f"{input_name}: {input_type},")
                 l("context: {},", self._import("grpc", "ServicerContext"))
             l(
                 ") -> {}:{}",
@@ -776,7 +785,7 @@ class PkgWriter(object):
             l("{}: {}[", method.name, self._callable_type(method))
             with self._indent():
                 l("{},", self._input_type(method, False))
-                l("{}] = ...", self._output_type(method, False))
+                l("{}]", self._output_type(method, False))
             self._write_comments(scl)
             l("")
 
@@ -793,7 +802,7 @@ class PkgWriter(object):
             scl = scl_prefix + [i]
 
             # The stub client
-            l("class {}Stub:", service.name)
+            l(f"class {service.name}Stub:")
             with self._indent():
                 self._write_comments(scl)
                 l(
@@ -852,7 +861,7 @@ class PkgWriter(object):
             d.FieldDescriptorProto.TYPE_STRING: lambda: self._import("typing", "Text"),
             d.FieldDescriptorProto.TYPE_BYTES: lambda: self._builtin("bytes"),
             d.FieldDescriptorProto.TYPE_ENUM: lambda: self._import_message(
-                field.type_name + ".V"
+                field.type_name + ".ValueType"
             ),
             d.FieldDescriptorProto.TYPE_MESSAGE: lambda: self._import_message(
                 field.type_name
@@ -879,7 +888,7 @@ class PkgWriter(object):
                     "RepeatedScalarFieldContainer",
                 )
             )
-            return "{}[{}]".format(container, field_type)
+            return f"{container}[{field_type}]"
 
         # non-scalar repeated map fields go in ScalarMap/MessageMap
         msg = self.descriptors.messages[field.type_name]
@@ -896,7 +905,7 @@ class PkgWriter(object):
                     "google.protobuf.internal.containers", "MessageMap"
                 )
             ktype, vtype = self._map_key_value_types(field, msg.field[0], msg.field[1])
-            return "{}[{}, {}]".format(container, ktype, vtype)
+            return f"{container}[{ktype}, {vtype}]"
 
         # non-scalar repetated fields go in RepeatedCompositeFieldContainer
         container = (
@@ -907,7 +916,7 @@ class PkgWriter(object):
                 "RepeatedCompositeFieldContainer",
             )
         )
-        return "{}[{}]".format(container, field_type)
+        return f"{container}[{field_type}]"
 
     def write(self) -> str:
         for reexport_idx in self.fd.public_dependency:
@@ -931,16 +940,16 @@ class PkgWriter(object):
 
         import_lines = []
         for pkg in sorted(self.imports):
-            import_lines.append(u"import {}".format(pkg))
+            import_lines.append(f"import {pkg}")
 
         for pkg, items in sorted(self.from_imports.items()):
-            import_lines.append(u"from {} import (".format(pkg))
+            import_lines.append(f"from {pkg} import (")
             for (name, reexport_name) in sorted(items):
                 if reexport_name is None:
-                    import_lines.append(u"    {},".format(name))
+                    import_lines.append(f"    {name},")
                 else:
-                    import_lines.append(u"    {} as {},".format(name, reexport_name))
-            import_lines.append(u")\n")
+                    import_lines.append(f"    {name} as {reexport_name},")
+            import_lines.append(")\n")
         import_lines.append("")
 
         return "\n".join(import_lines + self.lines)