From 43eb3f91c86695ff6ba2fd3e96cffe4de29bc5a8 Mon Sep 17 00:00:00 2001 From: jrmccluskey Date: Thu, 23 Apr 2026 09:58:43 -0400 Subject: [PATCH 1/5] Make Beartype use the default behavior in is_consistent_with() --- .../apache_beam/options/pipeline_options.py | 5 ++++ .../python/apache_beam/typehints/typehints.py | 18 ++++++++++++- .../apache_beam/typehints/typehints_test.py | 26 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/sdks/python/apache_beam/options/pipeline_options.py b/sdks/python/apache_beam/options/pipeline_options.py index d60d75283eab..163729d24dd7 100644 --- a/sdks/python/apache_beam/options/pipeline_options.py +++ b/sdks/python/apache_beam/options/pipeline_options.py @@ -886,6 +886,11 @@ def _add_argparse_args(cls, parser): action='store_false', help='Disable type checking at pipeline construction ' 'time') + parser.add_argument( + '--disable_beartype', + default=False, + action='store_true', + help='Disable the use of beartype for type checking.') parser.add_argument( '--runtime_type_check', default=False, diff --git a/sdks/python/apache_beam/typehints/typehints.py b/sdks/python/apache_beam/typehints/typehints.py index f429935c3a0e..139b084de517 100644 --- a/sdks/python/apache_beam/typehints/typehints.py +++ b/sdks/python/apache_beam/typehints/typehints.py @@ -66,6 +66,7 @@ # pytype: skip-file import copy +import functools import logging import types import typing @@ -1485,7 +1486,14 @@ def normalize(x, none_as_type=False): }) -def is_consistent_with(sub, base, use_beartype: bool = False) -> bool: +@functools.lru_cache(maxsize=128) +def _is_beartype_disabled(options): + from apache_beam.options.pipeline_options import TypeOptions + return options.view_as(TypeOptions).disable_beartype + + +def is_consistent_with( + sub, base, use_beartype: typing.Optional[bool] = None) -> bool: """Checks whether sub a is consistent with base. This is according to the terminology of PEP 483/484. This relationship is @@ -1494,6 +1502,14 @@ def is_consistent_with(sub, base, use_beartype: bool = False) -> bool: relation, but also handles the special Any type as well as type parameterization. """ + if use_beartype is None: + from apache_beam.options.pipeline_options_context import get_pipeline_options + options = get_pipeline_options() + if options: + use_beartype = not _is_beartype_disabled(options) + else: + use_beartype = True + from apache_beam.pvalue import Row from apache_beam.typehints.row_type import RowTypeConstraint if sub == base: diff --git a/sdks/python/apache_beam/typehints/typehints_test.py b/sdks/python/apache_beam/typehints/typehints_test.py index 992c129fd8a5..0b5ba62b80dd 100644 --- a/sdks/python/apache_beam/typehints/typehints_test.py +++ b/sdks/python/apache_beam/typehints/typehints_test.py @@ -1613,6 +1613,32 @@ def test_hint_helper_pipe_union(self): self.assertTrue(is_consistent_with(int, pipe_union_2)) self.assertTrue(is_consistent_with(float, pipe_union_2)) + def test_is_consistent_with_disable_beartype(self): + import unittest.mock + from apache_beam.options.pipeline_options import PipelineOptions + from apache_beam.options.pipeline_options_context import scoped_pipeline_options + + with unittest.mock.patch( + 'apache_beam.typehints.typehints.is_subhint') as mock_is_subhint: + mock_is_subhint.return_value = True + + class A: + pass + + class B(A): + pass + + options = PipelineOptions([]) + with scoped_pipeline_options(options): + typehints.is_consistent_with(B, A) + self.assertTrue(mock_is_subhint.called) + mock_is_subhint.reset_mock() + + options = PipelineOptions(['--disable_beartype']) + with scoped_pipeline_options(options): + typehints.is_consistent_with(B, A) + self.assertFalse(mock_is_subhint.called) + def test_positional_arg_hints(self): self.assertEqual(typehints.Any, _positional_arg_hints('x', {})) self.assertEqual(int, _positional_arg_hints('x', {'x': int})) From 32aa941e4cf03a6eea5a55c68f1abd6edb581f1b Mon Sep 17 00:00:00 2001 From: jrmccluskey Date: Thu, 23 Apr 2026 10:03:35 -0400 Subject: [PATCH 2/5] CHANGES.md callout --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index bdcbd3451c7b..61861354df37 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -74,6 +74,7 @@ compatible. Both coders can decode encoded bytes from the other coder ([#38139](https://github.com/apache/beam/issues/38139)). * (Python) Added type alias for with_exception_handling to be used for typehints. ([#38173](https://github.com/apache/beam/issues/38173)). +* (Python) Made Beartype the default fallback type checking tool. This can be disabled with the `--disable_beartype` pipeline option. ([#38275](https://github.com/apache/beam/issues/38275)) ## Breaking Changes From 4150c07f67dbdfc23712339f01e61bbc7c1fe7f9 Mon Sep 17 00:00:00 2001 From: jrmccluskey Date: Thu, 23 Apr 2026 10:13:19 -0400 Subject: [PATCH 3/5] review comment --- sdks/python/apache_beam/typehints/typehints.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sdks/python/apache_beam/typehints/typehints.py b/sdks/python/apache_beam/typehints/typehints.py index 139b084de517..bfd74ef7cd1a 100644 --- a/sdks/python/apache_beam/typehints/typehints.py +++ b/sdks/python/apache_beam/typehints/typehints.py @@ -66,7 +66,6 @@ # pytype: skip-file import copy -import functools import logging import types import typing @@ -1486,12 +1485,6 @@ def normalize(x, none_as_type=False): }) -@functools.lru_cache(maxsize=128) -def _is_beartype_disabled(options): - from apache_beam.options.pipeline_options import TypeOptions - return options.view_as(TypeOptions).disable_beartype - - def is_consistent_with( sub, base, use_beartype: typing.Optional[bool] = None) -> bool: """Checks whether sub a is consistent with base. @@ -1506,7 +1499,8 @@ def is_consistent_with( from apache_beam.options.pipeline_options_context import get_pipeline_options options = get_pipeline_options() if options: - use_beartype = not _is_beartype_disabled(options) + from apache_beam.options.pipeline_options import TypeOptions + use_beartype = not options.view_as(TypeOptions).disable_beartype else: use_beartype = True From c1e96c1b136174db710e03df4afdacd566f648ae Mon Sep 17 00:00:00 2001 From: Jack McCluskey <34928439+jrmccluskey@users.noreply.github.com> Date: Thu, 23 Apr 2026 10:14:49 -0400 Subject: [PATCH 4/5] Update CHANGES.md Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 61861354df37..efd6ea59f568 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -74,10 +74,11 @@ compatible. Both coders can decode encoded bytes from the other coder ([#38139](https://github.com/apache/beam/issues/38139)). * (Python) Added type alias for with_exception_handling to be used for typehints. ([#38173](https://github.com/apache/beam/issues/38173)). -* (Python) Made Beartype the default fallback type checking tool. This can be disabled with the `--disable_beartype` pipeline option. ([#38275](https://github.com/apache/beam/issues/38275)) +* (Python) Added type alias for with_exception_handling to be used for typehints. ([#38173](https://github.com/apache/beam/issues/38173)). ## Breaking Changes +* (Python) Made Beartype the default fallback type checking tool. This can be disabled with the `--disable_beartype` pipeline option. ([#38275](https://github.com/apache/beam/issues/38275)) * X behavior was changed ([#X](https://github.com/apache/beam/issues/X)). ## Deprecations From 49386e5a848bbaeaa589fb4aaf6cc17fedc18748 Mon Sep 17 00:00:00 2001 From: jrmccluskey Date: Thu, 23 Apr 2026 10:30:05 -0400 Subject: [PATCH 5/5] linting --- sdks/python/apache_beam/typehints/typehints_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdks/python/apache_beam/typehints/typehints_test.py b/sdks/python/apache_beam/typehints/typehints_test.py index 0b5ba62b80dd..3806f65ac429 100644 --- a/sdks/python/apache_beam/typehints/typehints_test.py +++ b/sdks/python/apache_beam/typehints/typehints_test.py @@ -1615,6 +1615,7 @@ def test_hint_helper_pipe_union(self): def test_is_consistent_with_disable_beartype(self): import unittest.mock + from apache_beam.options.pipeline_options import PipelineOptions from apache_beam.options.pipeline_options_context import scoped_pipeline_options