Skip to content

Commit 00bb7b5

Browse files
author
Nikita Grover
committed
Move Row to typehints/row.py, add compatibility alias in pvalue.py, update imports, and update CHANGES.md (Fixes #35095)
1 parent 7f47191 commit 00bb7b5

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@
7474

7575
* Support configuring Firestore database on ReadFn transforms (Java) ([#36904](https://github.com/apache/beam/issues/36904)).
7676

77+
* (Python) Moved `Row` to `apache_beam.typehints.row` to avoid import cycles and improve module organization. Kept a compatibility alias in `pvalue.py`. (Fixes #35095)
78+
79+
7780
## Breaking Changes
7881

7982
* (Python) Some Python dependencies have been split out into extras. To ensure all previously installed dependencies are installed, when installing Beam you can `pip install apache-beam[gcp,interactive,yaml,redis,hadoop,tfrecord]`, though most users will not need all of these extras ([#34554](https://github.com/apache/beam/issues/34554)).

sdks/python/apache_beam/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@
9090
from apache_beam import version
9191
from apache_beam.pipeline import *
9292
from apache_beam.pvalue import PCollection
93-
from apache_beam.pvalue import Row
9493
from apache_beam.pvalue import TaggedOutput
9594
from apache_beam.transforms import *
95+
from apache_beam.typehints.row import Row
9696

9797
try:
9898
# Add mitigation for CVE-2023-47248 while Beam allows affected versions

sdks/python/apache_beam/pvalue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from typing import Dict
3434
from typing import Generic
3535
from typing import Iterator
36-
from typing import NamedTuple
3736
from typing import Optional
3837
from typing import Sequence
3938
from typing import TypeVar
@@ -45,6 +44,7 @@
4544
from apache_beam.portability import common_urns
4645
from apache_beam.portability import python_urns
4746
from apache_beam.portability.api import beam_runner_api_pb2
47+
from apache_beam.typehints.row import Row, _make_Row
4848

4949
if TYPE_CHECKING:
5050
from apache_beam.pipeline import AppliedPTransform
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
from typing import NamedTuple
19+
20+
21+
class Row(object):
22+
"""A dynamic schema'd row object.
23+
24+
This objects attributes are initialized from the keywords passed into its
25+
constructor, e.g. Row(x=3, y=4) will create a Row with two attributes x and y.
26+
27+
More importantly, when a Row object is returned from a `Map`, `FlatMap`, or
28+
`DoFn` type inference is able to deduce the schema of the resulting
29+
PCollection, e.g.
30+
31+
pc | beam.Map(lambda x: Row(x=x, y=0.5 * x))
32+
33+
when applied to a PCollection of ints will produce a PCollection with schema
34+
`(x=int, y=float)`.
35+
36+
Note that in Beam 2.30.0 and later, Row objects are sensitive to field order.
37+
So `Row(x=3, y=4)` is not considered equal to `Row(y=4, x=3)`.
38+
"""
39+
def __init__(self, **kwargs):
40+
self.__dict__.update(kwargs)
41+
42+
def as_dict(self):
43+
return dict(self.__dict__)
44+
45+
# For compatibility with named tuples.
46+
_asdict = as_dict
47+
48+
def __iter__(self):
49+
for _, value in self.__dict__.items():
50+
yield value
51+
52+
def __repr__(self):
53+
return 'Row(%s)' % ', '.join('%s=%r' % kv for kv in self.__dict__.items())
54+
55+
def __hash__(self):
56+
return hash(self.__dict__.items())
57+
58+
def __eq__(self, other):
59+
if type(self) == type(other):
60+
other_dict = other.__dict__
61+
elif type(other) == type(NamedTuple):
62+
other_dict = other._asdict()
63+
else:
64+
return False
65+
return (
66+
len(self.__dict__) == len(other_dict) and
67+
all(s == o for s, o in zip(self.__dict__.items(), other_dict.items())))
68+
69+
def __reduce__(self):
70+
return _make_Row, tuple(self.__dict__.items())
71+
72+
73+
def _make_Row(*items):
74+
return Row(**dict(items))

0 commit comments

Comments
 (0)