Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,8 @@ repos:
args: ["--rcfile=sdks/python/.pylintrc"]
files: ^sdks/python/apache_beam/
exclude: *exclude
- repo: https://github.com/pycqa/isort
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added as CI runs isort but pre-commit doesn't. Should have same behavior as ci. The setup.cfg tweaks I did were to match run_pylint.sh in CI.

rev: 5.8.0
hooks:
- id: isort
name: isort (python)
21 changes: 20 additions & 1 deletion sdks/python/.coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,23 @@
#

[run]
omit = target/*
omit = target/*

[report]
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover
abc.abstractmethod

# Overload stubs should never be executed.
@overload

# Don't complain about missing debug-only code:
def __repr__
if self\.debug
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about: if self\.debug_logging_enabled to avoid pattern-matching with if self.debug_options which occurs in the codebase?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. The reason I did if self.debug was to make .coveragerc consistent with setup.cfg coverage option. For the infra pr I can make them both self.debug_logging_enabled


# Don't complain if tests don't hit defensive assertion code:
raise NotImplementedError

# Don't complain if non-runnable code isn't run:
if __name__ == .__main__.:
5 changes: 3 additions & 2 deletions sdks/python/apache_beam/runners/direct/transform_evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import atexit
import collections
import collections.abc
import logging
import random
import time
Expand Down Expand Up @@ -936,7 +937,7 @@ def process_element(self, element):
assert not self.global_state.get_state(
None, _GroupByKeyOnlyEvaluator.COMPLETION_TAG)
if (isinstance(element, WindowedValue) and
isinstance(element.value, collections.Iterable) and
isinstance(element.value, collections.abc.Iterable) and
len(element.value) == 2):
k, v = element.value
encoded_k = self.key_coder.encode(k)
Expand Down Expand Up @@ -1025,7 +1026,7 @@ def start_bundle(self):

def process_element(self, element):
if (isinstance(element, WindowedValue) and
isinstance(element.value, collections.Iterable) and
isinstance(element.value, collections.abc.Iterable) and
len(element.value) == 2):
k, v = element.value
self.gbk_items[self.key_coder.encode(k)].append(v)
Expand Down
3 changes: 2 additions & 1 deletion sdks/python/apache_beam/runners/worker/sideinputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# pytype: skip-file

import collections
import collections.abc
import logging
import queue
import threading
Expand Down Expand Up @@ -207,7 +208,7 @@ def _inner():
return _inner


class EmulatedIterable(collections.Iterable):
class EmulatedIterable(collections.abc.Iterable):
"""Emulates an iterable for a side input."""
def __init__(self, iterator_fn):
self.iterator_fn = iterator_fn
Expand Down
3 changes: 2 additions & 1 deletion sdks/python/apache_beam/transforms/trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# pytype: skip-file

import collections
import collections.abc
import copy
import logging
import numbers
Expand Down Expand Up @@ -1259,7 +1260,7 @@ def __reduce__(self):
return list, (list(self), )

def __eq__(self, other):
if isinstance(other, collections.Iterable):
if isinstance(other, collections.abc.Iterable):
return all(
a == b for a, b in zip_longest(self, other, fillvalue=object()))
else:
Expand Down
3 changes: 2 additions & 1 deletion sdks/python/apache_beam/typehints/typecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
# pytype: skip-file

import collections
import collections.abc
import inspect
import sys
import types
Expand Down Expand Up @@ -105,7 +106,7 @@ def _check_type(output):
'Returning a %s from a ParDo or FlatMap is '
'discouraged. Please use list("%s") if you really '
'want this behavior.' % (object_type, output))
elif not isinstance(output, collections.Iterable):
elif not isinstance(output, collections.abc.Iterable):
raise TypeCheckError(
'FlatMap and ParDo must return an '
'iterable. %s was returned instead.' % type(output))
Expand Down
9 changes: 5 additions & 4 deletions sdks/python/apache_beam/typehints/typehints.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
# pytype: skip-file

import collections
import collections.abc
import copy
import logging
import typing
Expand Down Expand Up @@ -532,7 +533,7 @@ def type_check(self, instance):
error_msg))

def __getitem__(self, type_params):
if not isinstance(type_params, (collections.Sequence, set)):
if not isinstance(type_params, (collections.abc.Sequence, set)):
raise TypeError('Cannot create Union without a sequence of types.')

# Flatten nested Union's and duplicated repeated type hints.
Expand Down Expand Up @@ -573,7 +574,7 @@ class OptionalHint(UnionHint):
"""
def __getitem__(self, py_type):
# A single type must have been passed.
if isinstance(py_type, collections.Sequence):
if isinstance(py_type, collections.abc.Sequence):
raise TypeError(
'An Option type-hint only accepts a single type '
'parameter.')
Expand Down Expand Up @@ -693,7 +694,7 @@ def bind_type_variables(self, bindings):
def __getitem__(self, type_params):
ellipsis = False

if not isinstance(type_params, collections.Iterable):
if not isinstance(type_params, collections.abc.Iterable):
# Special case for hinting tuples with arity-1.
type_params = (type_params, )

Expand Down Expand Up @@ -962,7 +963,7 @@ class IterableHint(CompositeTypeHint):
class IterableTypeConstraint(SequenceTypeConstraint):
def __init__(self, iter_type):
super(IterableHint.IterableTypeConstraint,
self).__init__(iter_type, collections.Iterable)
self).__init__(iter_type, collections.abc.Iterable)

def __repr__(self):
return 'Iterable[%s]' % _unified_repr(self.inner_type)
Expand Down
12 changes: 6 additions & 6 deletions sdks/python/apache_beam/utils/proto_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@
@overload
def pack_Any(msg):
# type: (message.Message) -> any_pb2.Any
pass
...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass vs ... are similar but not same. pass has an inferred return type of None for some type checkers. Pyright will give you an error for using pass here. ... is typical way to mark overloads as stubs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are test files even type checked? I tried running mypy on this file and got an error. Also discovered mypy.ini for the repo has an invalid value giving this error message,

mypy.ini: [mypy]: follow_imports: invalid choice 'true' (choose from 'normal', 'silent', 'skip', 'error')

The mypy error that prevents it from type checking this file is,

apache_beam/portability/api/metrics_pb2.pyi:117: error: invalid syntax [syntax] Looks like root cause of that error is a comment using type: notation for doc string and confusing it with standard type comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I think generated _pb2.py files should be excluded from the type checks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't know about this usage of Ellipsis. Found: https://mypy.readthedocs.io/en/stable/stubs.html and python/typing#109 where this is disussed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pb2.py is not type checked, but pb2.pyi is needed for type inference. Looks like proto file has a comment that confuses mypy. I can make a tweak to the comment to make it fine for mypy.



@overload
def pack_Any(msg):
# type: (None) -> None
pass
...


def pack_Any(msg):
Expand All @@ -65,13 +65,13 @@ def pack_Any(msg):
@overload
def unpack_Any(any_msg, msg_class):
# type: (any_pb2.Any, Type[MessageT]) -> MessageT
pass
...


@overload
def unpack_Any(any_msg, msg_class):
# type: (any_pb2.Any, None) -> None
pass
...


def unpack_Any(any_msg, msg_class):
Expand All @@ -89,13 +89,13 @@ def unpack_Any(any_msg, msg_class):
@overload
def parse_Bytes(serialized_bytes, msg_class):
# type: (bytes, Type[MessageT]) -> MessageT
pass
...


@overload
def parse_Bytes(serialized_bytes, msg_class):
# type: (bytes, Union[Type[bytes], None]) -> bytes
pass
...


def parse_Bytes(serialized_bytes, msg_class):
Expand Down
25 changes: 25 additions & 0 deletions sdks/python/apache_beam/utils/proto_utils_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import unittest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RAT check wants you to add a license here, see other files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you will fix.

from google.protobuf import timestamp_pb2

from apache_beam.utils.proto_utils import pack_Any
from apache_beam.utils.proto_utils import to_Timestamp
from apache_beam.utils.proto_utils import unpack_Any


class ProtoUtilsTest(unittest.TestCase):
def make_proto_timestamp(self):
# type: () -> timestamp_pb2.Timestamp
return to_Timestamp(0)

def test_none_pack(self):
packed_none = pack_Any(None)
assert packed_none is None

def test_date_pack(self):
# type: () -> None
proto_timestamp = self.make_proto_timestamp()
packed_msg = pack_Any(proto_timestamp)
orig_msg = unpack_Any(packed_msg, timestamp_pb2.Timestamp)
none_msg = unpack_Any(packed_msg, None)
assert proto_timestamp == orig_msg
assert none_msg is None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a left over given that you have a separate test_none_pack?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test_None_pack is to check packing None. unpack_Any does not allow None for the msg, but allows None for the msg type. So this is intended. I wanted to test both None msg pack and None class unpack.

7 changes: 7 additions & 0 deletions sdks/python/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ exclude_lines =
pragma: no cover
abc.abstractmethod

# Overload stubs should never be executed.
@overload

# Don't complain about missing debug-only code:
def __repr__
if self\.debug
Expand All @@ -53,7 +56,11 @@ exclude_lines =
output = target/site/cobertura/coverage.xml

[isort]
line_length = 120
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this number come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Came across https://issues.apache.org/jira/browse/BEAM-3745 with touches on isort & lint. perhaps we can close it already or after your changes.

known_standard_library = dataclasses
force_single_line = True
combine_star = True
order_by_type = True

[yapf]
indent_width = 2
Expand Down