Skip to content

Commit 69b7026

Browse files
claudevdmtvalentyn
andauthored
Add ability for coders to set version tags for update compat checks. (#36316)
* Add ability for coders to set version tags for update compat checks. * Fix lint. * Update docstring. * Update sdks/python/apache_beam/coders/coders.py * Update sdks/python/apache_beam/coders/coders.py --------- Co-authored-by: tvalentyn <tvalentyn@users.noreply.github.com>
1 parent 2f9a910 commit 69b7026

3 files changed

Lines changed: 44 additions & 0 deletions

File tree

sdks/python/apache_beam/coders/coders.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,15 @@ def from_runner_api_parameter(unused_payload, components, unused_context):
395395
else:
396396
return cls()
397397

398+
def version_tag(self) -> str:
399+
"""For internal use. Appends a version tag to the coder key in the pipeline
400+
proto. Some runners (e.g. DataflowRunner) use coder key/id to verify if a
401+
pipeline is update compatible. If the implementation of a coder changed
402+
in an update incompatible way a version tag can be added to fail compat
403+
compatibility checks.
404+
"""
405+
return ""
406+
398407

399408
@Coder.register_urn(
400409
python_urns.PICKLED_CODER, google.protobuf.wrappers_pb2.BytesValue)

sdks/python/apache_beam/pipeline.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,5 +1712,7 @@ def _unique_ref(self, obj=None, obj_type=None, label=None):
17121712
prefix = self._normalize(
17131713
'%s_%s_%s' %
17141714
(self.namespace, obj_type.__name__, label or type(obj).__name__))[0:100]
1715+
if isinstance(obj, typecoders.coders.Coder) and obj.version_tag():
1716+
prefix = "%s_%s" % (prefix, obj.version_tag())
17151717
self._counters[obj_type] += 1
17161718
return '%s_%d' % (prefix, self._counters[obj_type])

sdks/python/apache_beam/pipeline_test.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import pytest
2929

3030
import apache_beam as beam
31+
from apache_beam import coders
3132
from apache_beam import typehints
3233
from apache_beam.coders import BytesCoder
3334
from apache_beam.io import Read
@@ -1075,6 +1076,38 @@ def test_requirements(self):
10751076
common_urns.requirements.REQUIRES_BUNDLE_FINALIZATION.urn,
10761077
proto.requirements)
10771078

1079+
def test_coder_version_tag_included_in_runner_api_key(self):
1080+
class MyClass:
1081+
def __init__(self, value: int):
1082+
self.value = value
1083+
1084+
class VersionedCoder(coders.Coder):
1085+
def encode(self, value):
1086+
return str(value.value).encode()
1087+
1088+
def decode(self, encoded):
1089+
return MyClass(int(encoded.decode()))
1090+
1091+
def version_tag(self):
1092+
return "v269"
1093+
1094+
def to_type_hint(self):
1095+
return MyClass
1096+
1097+
coders.registry.register_coder(MyClass, VersionedCoder)
1098+
p = beam.Pipeline()
1099+
_ = (p | beam.Impulse() | beam.Map(lambda _: MyClass(1)))
1100+
pipeline_proto = p.to_runner_api()
1101+
coder_keys = sorted(list(pipeline_proto.components.coders.keys()))
1102+
1103+
self.assertListEqual(
1104+
coder_keys,
1105+
[
1106+
'ref_Coder_BytesCoder_1',
1107+
'ref_Coder_GlobalWindowCoder_2',
1108+
'ref_Coder_VersionedCoder_v269_3'
1109+
])
1110+
10781111
def test_annotations(self):
10791112
some_proto = BytesCoder().to_runner_api(None)
10801113

0 commit comments

Comments
 (0)