Skip to content

Commit 95339bf

Browse files
authored
Misc cleanup, see commit body (#227)
- Enable oneof_enum test case that passes now (removed the xfail) - Switch from toml to tomlkit as a dev dep for better toml support - upgrade poethepoet to latest stable release - use full table format for poe tasks to avoid long lines in pyproject.toml - remove redundant _WrappedMessage class - fix various Mypy warnings - reformat some comments for consistent line length
1 parent 5b639c8 commit 95339bf

File tree

9 files changed

+140
-120
lines changed

9 files changed

+140
-120
lines changed

poetry.lock

Lines changed: 67 additions & 67 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jinja2 = { version = "^2.11.2", optional = true }
2020
python-dateutil = "^2.8"
2121

2222
[tool.poetry.dev-dependencies]
23+
asv = "^0.4.2"
2324
black = "^20.8b1"
2425
bpython = "^0.19"
2526
grpcio-tools = "^1.30.0"
@@ -31,11 +32,10 @@ pytest = "^5.4.2"
3132
pytest-asyncio = "^0.12.0"
3233
pytest-cov = "^2.9.0"
3334
pytest-mock = "^3.1.1"
34-
toml = "^0.10.1"
35-
tox = "^3.15.1"
3635
sphinx = "3.1.2"
3736
sphinx-rtd-theme = "0.5.0"
38-
asv = "^0.4.2"
37+
tomlkit = "^0.7.0"
38+
tox = "^3.15.1"
3939

4040

4141
[tool.poetry.scripts]
@@ -44,29 +44,62 @@ protoc-gen-python_betterproto = "betterproto.plugin:main"
4444
[tool.poetry.extras]
4545
compiler = ["black", "jinja2"]
4646

47-
[tool.poe.tasks]
47+
4848
# Dev workflow tasks
49-
generate = { script = "tests.generate:main", help = "Generate test cases (do this once before running test)" }
50-
test = { cmd = "pytest --cov src", help = "Run tests" }
51-
types = { cmd = "mypy src --ignore-missing-imports", help = "Check types with mypy" }
52-
format = { cmd = "black . --exclude tests/output_", help = "Apply black formatting to source code" }
53-
docs = { cmd = "sphinx-build docs docs/build", help = "Build the sphinx docs"}
54-
bench = { shell = "asv run master^! && asv run HEAD^! && asv compare master HEAD", help = "Benchmark current commit vs. master branch"}
55-
clean = { cmd = "rm -rf .asv .coverage .mypy_cache .pytest_cache dist betterproto.egg-info **/__pycache__ tests/output_*", help = "Clean out generated files from the workspace" }
56-
57-
generate_lib.cmd = """
49+
50+
[tool.poe.tasks.generate]
51+
script = "tests.generate:main"
52+
help = "Generate test cases (do this once before running test)"
53+
54+
[tool.poe.tasks.test]
55+
cmd = "pytest"
56+
help = "Run tests"
57+
58+
[tool.poe.tasks.types]
59+
cmd = "mypy src --ignore-missing-imports"
60+
help = "Check types with mypy"
61+
62+
[tool.poe.tasks.format]
63+
cmd = "black . --exclude tests/output_"
64+
help = "Apply black formatting to source code"
65+
66+
[tool.poe.tasks.docs]
67+
cmd = "sphinx-build docs docs/build"
68+
help = "Build the sphinx docs"
69+
70+
[tool.poe.tasks.bench]
71+
shell = "asv run master^! && asv run HEAD^! && asv compare master HEAD"
72+
help = "Benchmark current commit vs. master branch"
73+
74+
[tool.poe.tasks.clean]
75+
cmd = """
76+
rm -rf .asv .coverage .mypy_cache .pytest_cache
77+
dist betterproto.egg-info **/__pycache__
78+
testsoutput_*
79+
"""
80+
help = "Clean out generated files from the workspace"
81+
82+
[tool.poe.tasks.generate_lib]
83+
cmd = """
5884
protoc
5985
--plugin=protoc-gen-custom=src/betterproto/plugin/main.py
6086
--custom_opt=INCLUDE_GOOGLE
6187
--custom_out=src/betterproto/lib
6288
-I /usr/local/include/
6389
/usr/local/include/google/protobuf/**/*.proto
6490
"""
65-
generate_lib.help = "Regenerate the types in betterproto.lib.google"
91+
help = "Regenerate the types in betterproto.lib.google"
6692

6793
# CI tasks
68-
full-test = { shell = "poe generate && tox", help = "Run tests with multiple pythons" }
69-
check-style = { cmd = "black . --check --diff --exclude tests/output_", help = "Check if code style is correct"}
94+
95+
[tool.poe.tasks.full-test]
96+
shell = "poe generate && tox"
97+
help = "Run tests with multiple pythons"
98+
99+
[tool.poe.tasks.check-style]
100+
cmd = "black . --check --diff --exclude tests/output_"
101+
help = "Check if code style is correct"
102+
70103

71104
[tool.black]
72105
target-version = ['py36']

src/betterproto/__init__.py

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
Callable,
1616
Dict,
1717
Generator,
18+
Iterable,
1819
List,
1920
Optional,
2021
Set,
@@ -272,7 +273,7 @@ def from_string(cls, name: str) -> "Enum":
272273
The member was not found in the Enum.
273274
"""
274275
try:
275-
return cls._member_map_[name]
276+
return cls._member_map_[name] # type: ignore
276277
except KeyError as e:
277278
raise ValueError(f"Unknown value {name} for enum {cls.__name__}") from e
278279

@@ -522,13 +523,13 @@ def __init__(self, cls: Type["Message"]):
522523

523524
@staticmethod
524525
def _get_default_gen(
525-
cls: Type["Message"], fields: List[dataclasses.Field]
526+
cls: Type["Message"], fields: Iterable[dataclasses.Field]
526527
) -> Dict[str, Callable[[], Any]]:
527528
return {field.name: cls._get_field_default_gen(field) for field in fields}
528529

529530
@staticmethod
530531
def _get_cls_by_field(
531-
cls: Type["Message"], fields: List[dataclasses.Field]
532+
cls: Type["Message"], fields: Iterable[dataclasses.Field]
532533
) -> Dict[str, Type]:
533534
field_cls = {}
534535

@@ -687,7 +688,7 @@ def _betterproto(self) -> ProtoClassMetadata:
687688
meta = getattr(self.__class__, "_betterproto_meta", None)
688689
if not meta:
689690
meta = ProtoClassMetadata(self.__class__)
690-
self.__class__._betterproto_meta = meta
691+
self.__class__._betterproto_meta = meta # type: ignore
691692
return meta
692693

693694
def __bytes__(self) -> bytes:
@@ -763,7 +764,7 @@ def __bytes__(self) -> bytes:
763764
meta.number,
764765
meta.proto_type,
765766
value,
766-
serialize_empty=serialize_empty or selected_in_group,
767+
serialize_empty=serialize_empty or bool(selected_in_group),
767768
wraps=meta.wraps or "",
768769
)
769770

@@ -1067,7 +1068,7 @@ def to_dict(
10671068
output[cased_name] = b64encode(value).decode("utf8")
10681069
elif meta.proto_type == TYPE_ENUM:
10691070
if field_is_repeated:
1070-
enum_class: Type[Enum] = field_types[field_name].__args__[0]
1071+
enum_class = field_types[field_name].__args__[0]
10711072
if isinstance(value, typing.Iterable) and not isinstance(
10721073
value, str
10731074
):
@@ -1076,7 +1077,7 @@ def to_dict(
10761077
# transparently upgrade single value to repeated
10771078
output[cased_name] = [enum_class(value).name]
10781079
else:
1079-
enum_class: Type[Enum] = field_types[field_name] # noqa
1080+
enum_class = field_types[field_name] # noqa
10801081
output[cased_name] = enum_class(value).name
10811082
elif meta.proto_type in (TYPE_FLOAT, TYPE_DOUBLE):
10821083
if field_is_repeated:
@@ -1293,23 +1294,6 @@ def timestamp_to_json(dt: datetime) -> str:
12931294
return f"{result}.{nanos:09d}"
12941295

12951296

1296-
class _WrappedMessage(Message):
1297-
"""
1298-
Google protobuf wrapper types base class. JSON representation is just the
1299-
value itself.
1300-
"""
1301-
1302-
value: Any
1303-
1304-
def to_dict(self, casing: Casing = Casing.CAMEL) -> Any:
1305-
return self.value
1306-
1307-
def from_dict(self: T, value: Any) -> T:
1308-
if value is not None:
1309-
self.value = value
1310-
return self
1311-
1312-
13131297
def _get_wrapper(proto_type: str) -> Type:
13141298
"""Get the wrapper message class for a wrapped type."""
13151299

src/betterproto/compile/importing.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ def reference_descendent(
100100
current_package: List[str], imports: Set[str], py_package: List[str], py_type: str
101101
) -> str:
102102
"""
103-
Returns a reference to a python type in a package that is a descendent of the current package,
104-
and adds the required import that is aliased to avoid name conflicts.
103+
Returns a reference to a python type in a package that is a descendent of the
104+
current package, and adds the required import that is aliased to avoid name
105+
conflicts.
105106
"""
106107
importing_descendent = py_package[len(current_package) :]
107108
string_from = ".".join(importing_descendent[:-1])
@@ -119,8 +120,9 @@ def reference_ancestor(
119120
current_package: List[str], imports: Set[str], py_package: List[str], py_type: str
120121
) -> str:
121122
"""
122-
Returns a reference to a python type in a package which is an ancestor to the current package,
123-
and adds the required import that is aliased (if possible) to avoid name conflicts.
123+
Returns a reference to a python type in a package which is an ancestor to the
124+
current package, and adds the required import that is aliased (if possible) to avoid
125+
name conflicts.
124126
125127
Adds trailing __ to avoid name mangling (python.org/dev/peps/pep-0008/#id34).
126128
"""
@@ -141,10 +143,10 @@ def reference_cousin(
141143
current_package: List[str], imports: Set[str], py_package: List[str], py_type: str
142144
) -> str:
143145
"""
144-
Returns a reference to a python type in a package that is not descendent, ancestor or sibling,
145-
and adds the required import that is aliased to avoid name conflicts.
146+
Returns a reference to a python type in a package that is not descendent, ancestor
147+
or sibling, and adds the required import that is aliased to avoid name conflicts.
146148
"""
147-
shared_ancestry = os.path.commonprefix([current_package, py_package])
149+
shared_ancestry = os.path.commonprefix([current_package, py_package]) # type: ignore
148150
distance_up = len(current_package) - len(shared_ancestry)
149151
string_from = f".{'.' * distance_up}" + ".".join(
150152
py_package[len(shared_ancestry) : -1]

src/betterproto/grpc/util/async_channel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class AsyncChannel(AsyncIterable[T]):
7070
"""
7171

7272
def __init__(self, *, buffer_limit: int = 0, close: bool = False):
73-
self._queue: asyncio.Queue[Union[T, object]] = asyncio.Queue(buffer_limit)
73+
self._queue: asyncio.Queue[T] = asyncio.Queue(buffer_limit)
7474
self._closed = False
7575
self._waiting_receivers: int = 0
7676
# Track whether flush has been invoked so it can only happen once

src/betterproto/plugin/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ class ProtoContentBase:
170170
comment_indent: int = 4
171171
parent: Union["betterproto.Message", "OutputTemplate"]
172172

173+
__dataclass_fields__: Dict[str, object]
174+
173175
def __post_init__(self) -> None:
174176
"""Checks that no fake default fields were left as placeholders."""
175177
for field_name, field_val in self.__dataclass_fields__.items():

src/betterproto/plugin/parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import itertools
1414
import pathlib
1515
import sys
16-
from typing import Iterator, List, Tuple, TYPE_CHECKING, Union
16+
from typing import Iterator, List, Set, Tuple, TYPE_CHECKING, Union
1717
from .compiler import outputfile_compiler
1818
from .models import (
1919
EnumDefinitionCompiler,
@@ -38,7 +38,7 @@ def traverse(
3838
) -> "itertools.chain[Tuple[Union[str, EnumDescriptorProto], List[int]]]":
3939
# Todo: Keep information about nested hierarchy
4040
def _traverse(
41-
path: List[int], items: List["Descriptor"], prefix=""
41+
path: List[int], items: List["EnumDescriptorProto"], prefix=""
4242
) -> Iterator[Tuple[Union[str, EnumDescriptorProto], List[int]]]:
4343
for i, item in enumerate(items):
4444
# Adjust the name since we flatten the hierarchy.

tests/inputs/config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Test cases that are expected to fail, e.g. unimplemented features or bug-fixes.
22
# Remove from list when fixed.
33
xfail = {
4-
"oneof_enum", # 63
54
"namespace_keywords", # 70
65
"namespace_builtin_types", # 53
76
"googletypes_struct", # 9

tests/test_version.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from betterproto import __version__
22
from pathlib import Path
3-
import toml
3+
import tomlkit
44

55
PROJECT_TOML = Path(__file__).joinpath("..", "..", "pyproject.toml").resolve()
66

77

88
def test_version():
99
with PROJECT_TOML.open() as toml_file:
10-
project_config = toml.load(toml_file)
10+
project_config = tomlkit.loads(toml_file.read())
1111
assert (
1212
__version__ == project_config["tool"]["poetry"]["version"]
1313
), "Project version should match in package and package config"

0 commit comments

Comments
 (0)