From c7b9cb81aec19831ec5862b8ccafe1a905b1e3b5 Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Mon, 9 Mar 2026 13:27:43 -0400 Subject: [PATCH 1/2] Reproduce help bug --- betterproto2/tests/README.md | 8 ++++---- betterproto2/tests/test_documentation.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/betterproto2/tests/README.md b/betterproto2/tests/README.md index f1ee609c..11825653 100644 --- a/betterproto2/tests/README.md +++ b/betterproto2/tests/README.md @@ -33,7 +33,7 @@ message Test { } ``` -You can add multiple `.proto` files to the test case, as long as one file matches the directory name. +You can add multiple `.proto` files to the test case, as long as one file matches the directory name. ### json @@ -64,11 +64,11 @@ The following tests are automatically executed for all cases: - [x] Can the generated python code be imported? - [x] Can the generated message class be instantiated? - [x] Is the generated code compatible with the Google's `grpc_tools.protoc` implementation? - - _when `.json` is present_ + - _when `.json` is present_ ## Running the tests -- `pipenv run generate` +- `pipenv run get-local-compiled-tests` This generates: - `betterproto/tests/output_betterproto` — *the plugin generated python classes* - `betterproto/tests/output_reference` — *reference implementation classes* @@ -88,4 +88,4 @@ betterproto/tests/test_inputs.py ..x...x..x...x.X........xx........x.....x...... - `x` — XFAIL: expected failure - `X` — XPASS: expected failure, but still passed -Test cases marked for expected failure are declared in [inputs/config.py](inputs/config.py) \ No newline at end of file +Test cases marked for expected failure are declared in [inputs/config.py](inputs/config.py) diff --git a/betterproto2/tests/test_documentation.py b/betterproto2/tests/test_documentation.py index 875c7872..60cb09bc 100644 --- a/betterproto2/tests/test_documentation.py +++ b/betterproto2/tests/test_documentation.py @@ -60,3 +60,13 @@ def test_escaping(requires_grpclib) -> None: Simple quotes are not escaped " """ ) + + +def test_help(requires_grpclib) -> None: + """Test that help(Foo) doesn't trigger an error.""" + from .outputs.documentation.documentation import Test + + # help(Test) triggers help(Message) + # which inspects the class attribute Message._betterproto + # which is only supposed to be defined on subclasses of Message. + help(Test) From 782e09adbe823182a87bb082094ff86941e18d9b Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Mon, 9 Mar 2026 13:31:15 -0400 Subject: [PATCH 2/2] Fix help bug --- betterproto2/src/betterproto2/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/betterproto2/src/betterproto2/__init__.py b/betterproto2/src/betterproto2/__init__.py index 98221ec1..d9245f2f 100644 --- a/betterproto2/src/betterproto2/__init__.py +++ b/betterproto2/src/betterproto2/__init__.py @@ -716,6 +716,9 @@ def _betterproto(cls: type[Self]) -> ProtoClassMetadata: # type: ignore try: return cls._betterproto_meta except AttributeError: + if cls is Message: + # We can't generate metadata for the base class, only subclasses. + return None # type: ignore cls._betterproto_meta = ProtoClassMetadata(cls) return cls._betterproto_meta