Skip to content

Conversation

jfuss
Copy link
Contributor

@jfuss jfuss commented May 9, 2018

Issue #, if available:

Description of changes:
This is a work in progress. Py3 is not fully supported but sending this to get early feedback while I try to get the rest of the tests running in Py (3.6, specifically).

Details of the commit:
Most of this was drop in replacements for methods:

  • .iteritems() -> .items()
  • .itervalues() -> values()
  • .keys() returns a view into the dictionary in Py3 (list in Py2). So where needed, wrapped the .keys() in a list().
  • Updated imports to be relative for modules that were in the same folder.
  • Needed to do some trickery with strings due to differences in Py3 and Py2. This only impacts the LogicalIdGenerator but is the most concerning (imo) and biggest potential to cause deployments for Api Gateway when customers don't expect. Please look over this part with a fine tooth comb!

All tests pass in Py3 except for the majority of the 'functional tests' in the test_translator.py. This is caused by:

  1. The deepsort is comparing elements of different types which is causing issues in Py3.
  2. The strings we generate for the exceptions are non-deterministic between Py2 and Py3.

Ways to resolve what is left:

  1. Move away from deepsort. This was written to use pytest and asserts. All new code is written using unittest where you can compare dict by self.assertEquals().
  2. I need to spend more time and dig a little deeper here. At the moment I don't have a clean way of solving. Suggestions always welcome!

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Jacob Fuss added 9 commits May 8, 2018 20:08
Without moving this to the __init__, the globals.py file will not run
in Py3 because it can't reference the constants.
In Py3, the function .iteritems() on a dict was removed and replaced
with .items().
In Py3, .itervalues() and .iteritems() was replaced with .values() and
.items(), respectfully.
In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.
In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.
Updated .iteritems() to items()
@brettstack
Copy link
Contributor

LGTM. Py2 tests are passing which is the main thing. I think we can merge this and address the remaining Py3 test issues in a separate PR.

@brettstack
Copy link
Contributor

@sanathkr can we get an approval for this and merge it, knowing that there is still work to be done to get us all the way to Py3?

data_hash = ""
if self.data_str:
data_hash = hashlib.sha1(bytes(self.data_str)).hexdigest()
utf_encoded_data_str = str(self.data_str).encode("utf8")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think Py2 default encoding is latin1. This may need to be updated to that but unsure.

Copy link

@eric-wieser eric-wieser May 24, 2018

Choose a reason for hiding this comment

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

What is the type of self.data_str?

  • If it's bytes (data_str = b'test'), then str(data_str) gives:
    • "b'test'" on python 3
    • b'test' on python 2 (correct)
  • If it's unicode (data_str = u'snowman: \u2603'), then str(data_str):
    • gives u'snowman: \u2603' on python 3
    • raises a UnicodeEncodeError on python 2

I think what you actually want here is:

unicode = type(u'')   # or from six import unicode
s = self.data_str
if isinstance(s, unicode):
    s = s.encode('utf-8')

Calling str here is likely to do bad things -

Copy link
Contributor

Choose a reason for hiding this comment

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

self.data_str is a string data - so in py2 it is instance of basestring and in py3 it is unicode. Your solution is correct. We should encode only if it is unicode and skip otherwise.

Choose a reason for hiding this comment

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

You could also just encode if sys.version_info.major >= 3.

@jfuss's remark about py2 default encoding is irrelvant here - data_str comes from json.dumps, which by default only outputs unicode codepoints that can be encoded to ascii

self._logical_id = logical_id
self._message = message

def __lt__(self, other):
Copy link
Contributor

Choose a reason for hiding this comment

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

What's this? Operator overloading in Python?

Copy link

Choose a reason for hiding this comment

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

Yeah, that's a magic method in Python-speak: https://rszalski.github.io/magicmethods/

@brettstack brettstack self-assigned this May 22, 2018
@brettstack brettstack changed the title WIP: feat: Py3 support feat: add support for Python 3 May 22, 2018
@sanathkr sanathkr changed the base branch from develop to py3-support May 24, 2018 19:25
@sanathkr sanathkr self-requested a review May 24, 2018 19:26
Copy link
Contributor

@sanathkr sanathkr left a comment

Choose a reason for hiding this comment

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

LGTM

@brettstack brettstack merged commit 5927fe9 into aws:py3-support May 24, 2018
@@ -1,9 +1,9 @@
from deployment_preference import DeploymentPreference
from .deployment_preference import DeploymentPreference

Choose a reason for hiding this comment

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

You should add from __future__ import absolute_import, which will make this fail on python 2 as well

aliases = [r.to_dict() for r in resources if r.resource_type == LambdaAlias.resource_type]

self.assertTrue("UpdatePolicy" not in aliases[0].values()[0])
self.assertTrue("UpdatePolicy" not in list(aliases[0].values())[0])

Choose a reason for hiding this comment

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

list(x.values())[0] is possibly faster as next(iter(x.values()))

@eric-wieser
Copy link

If you run python2 with the -3 argument, it will give warnings about any parts of the code that change behavior in python3

brettstack pushed a commit that referenced this pull request Jun 28, 2018
* refactor: Updated imports to by Py3 compliant

* refactor: Move class variable creation to constructor in globals.py

Without moving this to the __init__, the globals.py file will not run
in Py3 because it can't reference the constants.

* refactor: Update update_policy.py to be Py3 compliant

In Py3, the function .iteritems() on a dict was removed and replaced
with .items().

* refactor: Update deployment_preference_collection.py to be Py3 compliant

In Py3, .itervalues() and .iteritems() was replaced with .values() and
.items(), respectfully.

* refactor: Update swagger.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* refactor: Update intrinsics.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* Staging translator.py changes

Updated .iteritems() to items()

* refactor: More updating to be Py3 compliant

* refactor: Make hashing constisent between py2 and py3

* refactor: Make exceptions sortable to allow error case tests to pass in Py3
brettstack added a commit that referenced this pull request Jun 28, 2018
* feat: add support for Python 3 (#428)

* refactor: Updated imports to by Py3 compliant

* refactor: Move class variable creation to constructor in globals.py

Without moving this to the __init__, the globals.py file will not run
in Py3 because it can't reference the constants.

* refactor: Update update_policy.py to be Py3 compliant

In Py3, the function .iteritems() on a dict was removed and replaced
with .items().

* refactor: Update deployment_preference_collection.py to be Py3 compliant

In Py3, .itervalues() and .iteritems() was replaced with .values() and
.items(), respectfully.

* refactor: Update swagger.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* refactor: Update intrinsics.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* Staging translator.py changes

Updated .iteritems() to items()

* refactor: More updating to be Py3 compliant

* refactor: Make hashing constisent between py2 and py3

* refactor: Make exceptions sortable to allow error case tests to pass in Py3

* fix: add support for Python 3 (#445)

* refactor: Updated imports to by Py3 compliant

* refactor: Move class variable creation to constructor in globals.py

Without moving this to the __init__, the globals.py file will not run
in Py3 because it can't reference the constants.

* refactor: Update update_policy.py to be Py3 compliant

In Py3, the function .iteritems() on a dict was removed and replaced
with .items().

* refactor: Update deployment_preference_collection.py to be Py3 compliant

In Py3, .itervalues() and .iteritems() was replaced with .values() and
.items(), respectfully.

* refactor: Update swagger.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* refactor: Update intrinsics.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* Staging translator.py changes

Updated .iteritems() to items()

* refactor: More updating to be Py3 compliant

* refactor: Make hashing constisent between py2 and py3

* refactor: Make exceptions sortable to allow error case tests to pass in Py3

* feat: Run tox from Travis-CI

* feat: Update tox to run in Py2 and Py3

* refactor: Force sorting behavior to be Py2 compatible and update Deployment logicalid hash

* fix: Update tox to run tests against Py27 and Py36

* Update Travis config to run Py2 and Py3 tests in parallel

* Setting region env var in tox file for Travis to pick up

* Set AWS region in travis file

* Pass AWS_* env vars to tox

* Fixing ordering of resource types in Globals error message

* Py2/3 compatible implementation of string encoding for logicalId generator

Also added lots of comments explaining why/how the deep sorting of lists
work in unit tests

* Removing redundant usage of bytes
brettstack added a commit that referenced this pull request Jun 28, 2018
* feat: add support for Python 3 (#428)

* refactor: Updated imports to by Py3 compliant

* refactor: Move class variable creation to constructor in globals.py

Without moving this to the __init__, the globals.py file will not run
in Py3 because it can't reference the constants.

* refactor: Update update_policy.py to be Py3 compliant

In Py3, the function .iteritems() on a dict was removed and replaced
with .items().

* refactor: Update deployment_preference_collection.py to be Py3 compliant

In Py3, .itervalues() and .iteritems() was replaced with .values() and
.items(), respectfully.

* refactor: Update swagger.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* refactor: Update intrinsics.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* Staging translator.py changes

Updated .iteritems() to items()

* refactor: More updating to be Py3 compliant

* refactor: Make hashing constisent between py2 and py3

* refactor: Make exceptions sortable to allow error case tests to pass in Py3

* fix: add support for Python 3 (#445)

* refactor: Updated imports to by Py3 compliant

* refactor: Move class variable creation to constructor in globals.py

Without moving this to the __init__, the globals.py file will not run
in Py3 because it can't reference the constants.

* refactor: Update update_policy.py to be Py3 compliant

In Py3, the function .iteritems() on a dict was removed and replaced
with .items().

* refactor: Update deployment_preference_collection.py to be Py3 compliant

In Py3, .itervalues() and .iteritems() was replaced with .values() and
.items(), respectfully.

* refactor: Update swagger.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* refactor: Update intrinsics.py to be Py3 compliant

In Py3, the .keys() method on a dictionary returns a dict_keys object
that is a view into the dictionary. In Py2, it returns a list. To
support Py3, we need to convert the .keys() to a list.

* Staging translator.py changes

Updated .iteritems() to items()

* refactor: More updating to be Py3 compliant

* refactor: Make hashing constisent between py2 and py3

* refactor: Make exceptions sortable to allow error case tests to pass in Py3

* feat: Run tox from Travis-CI

* feat: Update tox to run in Py2 and Py3

* refactor: Force sorting behavior to be Py2 compatible and update Deployment logicalid hash

* fix: Update tox to run tests against Py27 and Py36

* Update Travis config to run Py2 and Py3 tests in parallel

* Setting region env var in tox file for Travis to pick up

* Set AWS region in travis file

* Pass AWS_* env vars to tox

* Fixing ordering of resource types in Globals error message

* Py2/3 compatible implementation of string encoding for logicalId generator

Also added lots of comments explaining why/how the deep sorting of lists
work in unit tests

* Removing redundant usage of bytes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants