Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First pass at Python2.7 compatibility #203

Merged
merged 15 commits into from
Oct 31, 2019
Merged

First pass at Python2.7 compatibility #203

merged 15 commits into from
Oct 31, 2019

Conversation

cguardia
Copy link
Contributor

This is the first pass at getting a 2.7 branch to run. It is not intended for detailed review, but more to give an idea of what needed changing, and to allow evaluation of the main compatibility issues. Note that some of these changes broke some 3.x tests as well, which will be addressed by future work on this.

@cguardia cguardia requested a review from chrisrossi September 17, 2019 08:41
@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Sep 17, 2019
@cguardia cguardia self-assigned this Oct 22, 2019
@cguardia
Copy link
Contributor Author

@chrisrossi @andrewsg This is almost ready, but I'm running into a problem with the kokoro build. Locally, I get 100% test coverage on 2.7, but kokoro fails because it reports only 99%. It does not say which code is not covered. Could someone try this out locally to see if you get the same result?

@cguardia
Copy link
Contributor Author

@chrisrossi @andrewsg never mind, found out how to fix the coverage issue. This is ready for review.

@cguardia cguardia changed the title DO NOT MERGE first pass at Python2.7 compatibility First pass at Python2.7 compatibility Oct 29, 2019
Copy link
Contributor

@chrisrossi chrisrossi left a comment

Choose a reason for hiding this comment

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

LGTM, with notes.

]
# If there are any positional arguments, get their names.
# inspect.signature is not available in Python 2.7, so we use the
# arguments obtained with inspect.getarspec, which come from the
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo in inspect.getargspec.

@@ -59,6 +58,8 @@ def options(cls, wrapped):
in_options = True

elif in_options and name != "_options":
print(slots)
Copy link
Contributor

Choose a reason for hiding this comment

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

Some debugging code that got left in?

@@ -381,21 +383,25 @@ def __eq__(self, other):
def __lt__(self, other):
"""Less than ordering."""
if not isinstance(other, Key):
return NotImplemented
raise TypeError
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought NotImplemented was also the protocol for Python 2 comparison functions. Am I mistaken?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure about the protocol, but it just didn't work. The NotImplemented was being evaluated as an expression and returned a True/False value instead of raising.

@@ -460,7 +466,7 @@ def __getnewargs__(self):
state to pickle. The dictionary has three keys ``pairs``, ``app``
and ``namespace``.
"""
return (
return ( # pragma: NO COVER
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we unable to test this for some reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

_getnewargs is never called in Python 2 code. Might change the NO COVER to NO PY2 COVER.

@@ -1410,7 +1428,7 @@ def _clean_flat_path(flat):
raise exceptions.BadArgumentError(
"Incomplete Key entry must be last"
)
elif not isinstance(id_, (str, int)):
elif not isinstance(id_, (str,) + six.integer_types):
Copy link
Contributor

Choose a reason for hiding this comment

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

six.string_types?

@@ -3836,7 +3783,9 @@ def _comparison(self, op, value):
value = self._do_validate(value)
filters = []
match_keys = []
for prop in self._model_class._properties.values():
# Somehow, Python 2 and 3 return values in diiferent order, sort them.
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: different

Also, is there a production reason to sort them, or is it only to provide consistent ordering in unit tests? If the latter, I'd tend to sort in the test rather than in the code proper.

traceback = self._exception.__traceback__
except AttributeError: # pragma: NO PY3 COVER # pragma: NO BRANCH
# Python 2 does not have the helpful traceback attribute, and
# sice the exception is not being handled, it appears that
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: since

# Python 2 does not have the helpful traceback attribute, and
# sice the exception is not being handled, it appears that
# sys.exec_info can't give us the traceback either.
traceback = None
Copy link
Contributor

Choose a reason for hiding this comment

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

I think old NDB had some way to do this. Peek that code?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far a I can see, it just returns a traceback when it was specifically set by set_exception:

https://github.com/GoogleCloudPlatform/datastore-ndb-python/blob/master/ndb/tasklets.py#L331


query = SomeKind.query().order(SomeKind.foo)
assert query.map(get_other_foo) == foos
# TODO: the return with values inside the tasklet crashes tests on Python 2.7
Copy link
Contributor

Choose a reason for hiding this comment

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

You can just convert these to use "raise Return(x)" instead of "return x". Or if we want to test both, we can run different tests for python 2 and python 3. "@pytest.mark.skipif" is handy for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Turns out it errors out before even running the tests if the return is there, but I'll use the raise Return method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants