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

[WIP] Python 3 support #542

Merged
merged 37 commits into from
Oct 17, 2018
Merged

[WIP] Python 3 support #542

merged 37 commits into from
Oct 17, 2018

Conversation

pbauer
Copy link
Member

@pbauer pbauer commented Jun 22, 2018

No description provided.

@tisto
Copy link
Member

tisto commented Jun 23, 2018

@pbauer wohoo! Are you sprinting remotely? Wanna do a video call connection? That worked quite well with Asko at the last sprint. :)

@pbauer
Copy link
Member Author

pbauer commented Jun 23, 2018

Not really, I simply tried to get it running. The main issue for now is that plone.restapi tests have a hard dependency on Archetypes 😭. You should get rid of that. Then I will continue porting it to python 3.

@tisto
Copy link
Member

tisto commented Jun 23, 2018

@pbauer right. This dependency should be purely optional though. cc @lukasgraf @buchi

@lukasgraf
Copy link
Member

@pbauer in what way is the AT dependency causing issues for you?
I'm asking because I was thinking that we could move it to a separate extra instead of [test], like [test_archetypes], and then adjust .travis.yml to have Travis run those separately (on Python 2.7).

But that would probably not solve your issue either I would assume. So is the only option to remove the AT dependency entirely, and have the AT parts completely untested (via CI)?

@pbauer
Copy link
Member Author

pbauer commented Jun 24, 2018

@lukasgraf that would be good. Then we need to make all code, tests and test-layers that use archetypes optional depending on if AT can be imported or not.

@lukasgraf
Copy link
Member

@pbauer I see - so it's mostly about the imports in the test code failing if AT isn't available, not so much about the actual package dependency in the [test] extra. We can make that work:

  • Make AT imports conditional
  • Skip AT tests if AT isn't available
  • Use ZCML conditions to only run ZCML that requires AT if it's actually present
  • Possibly move all the AT tests into separate Python modules

@davisagli
Copy link
Member

I did a similar approach for plone.app.iterate: plone/plone.app.iterate#61

@pbauer
Copy link
Member Author

pbauer commented Jun 28, 2018

I was a little annoyed by the merge of plone.restapi ruining the python3 build.
So I hacked at the separation from AT this morning. Instead of breakfast, so now I'm hungry 🤔

The problem was not only the tests, there also are hard imports from Products.Archetypes in restapi itself (e.g. in services/content/add.py) and several places where the code seems to bew ritten wit AT as default content in mind.

This PR is by no menas done but I have to focus on other tasks for now so please either continue working on this or start the separation and porting to python 3 fresh.

@pbauer
Copy link
Member Author

pbauer commented Jun 28, 2018

By the way, tests of plone.restapi in py3 are currently: 863 tests, 47 failures, 135 errors, 115 skipped. Many of the failures and errors are due to the unfinished migration of plone.rest.

@lukasgraf
Copy link
Member

@pbauer

hard imports from Products.Archetypes in restapi itself (e.g. in services/content/add.py) and several places where the code seems to bew ritten wit AT as default content in mind.

That is definitely unintended and we need to fix this. Thanks for your efforts!

@tisto tisto changed the title Python 3 support [WIP] Python 3 support Jun 28, 2018
@tisto
Copy link
Member

tisto commented Jun 28, 2018

I think we should separate the Python 3 migration from getting rid of the AT dependency. Let's do the latter first and the look into Python 3 as Philip wrote.

@hvelarde
Copy link
Member

hvelarde commented Jul 13, 2018

tests are failing and branch needs a rebase, but this seems to be almost ready now:

$ pylint --py3k --disable=no-absolute-import src/plone/restapi/
No config file found, using default configuration

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)

from zope.interface import Interface
from zope.interface import implementer

from .mixins import OrderingMixin
Copy link
Member

Choose a reason for hiding this comment

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

this should be an absolute import instead.

Copy link
Member

Choose a reason for hiding this comment

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

+1

if pre_errors is not None:
for field_name, error_message in pre_errors.items():
if field_name in errors:
errors[field_name] += " %s" % error_message
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use single quotes and .format() instead?

Copy link
Member

Choose a reason for hiding this comment

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

If we don't enforce such a style decision we shouldn't require people to stick with it IMHO.

if post_errors is not None:
for field_name, error_message in post_errors.items():
if field_name in errors:
errors[field_name] += " %s" % error_message
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use single quotes and .format() instead?

if version == 'current':
return self.context
else:
repo_tool = getToolByName(self.context, "portal_repository")
Copy link
Member

Choose a reason for hiding this comment

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

we should use single quotes here.

from zope.interface import implementer

try:
from Products.CMFPlone.factory import _IMREALLYPLONE5 # noqa
Copy link
Member

Choose a reason for hiding this comment

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

this # noqa needs to be more specific.

@@ -79,8 +79,8 @@ def traverse(self, path='/plone', accept='application/json', method='GET'):
request.environ['PATH_TRANSLATED'] = path
request.environ['HTTP_ACCEPT'] = accept
request.environ['REQUEST_METHOD'] = method
request._auth = 'Basic %s' % b64encode(
'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use .format() instead?

request._auth = 'Basic %s' % b64encode(
'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
request._auth = 'Basic %s' % b64encode(auth.encode('utf8')).decode('utf8')
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use .format() instead?

@@ -34,8 +34,8 @@ def traverse(self, path='/plone', accept='application/json', method='GET'):
request.environ['PATH_TRANSLATED'] = path
request.environ['HTTP_ACCEPT'] = accept
request.environ['REQUEST_METHOD'] = method
request._auth = 'Basic %s' % b64encode(
'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use .format() instead?

request._auth = 'Basic %s' % b64encode(
'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
request._auth = 'Basic %s' % b64encode(auth.encode('utf8')).decode('utf8')
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use .format() instead?

@@ -39,7 +43,7 @@ def test_batched(self):
obj = self.serialize(registry)
expected = ['@id', 'items_total', 'items', 'batching']
self.assertEqual(set(expected), set(obj.keys()))
self.assertEqual(obj['items_total'], len(range(1, 100)))
self.assertEqual(obj['items_total'], len(list(range(1, 100))))
Copy link
Member

Choose a reason for hiding this comment

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

this should be written: self.assertEqual(obj['items_total'], 99)

@@ -98,8 +98,8 @@ def traverse(self, path='/plone', accept='application/json',
request.environ['PATH_TRANSLATED'] = path
request.environ['HTTP_ACCEPT'] = accept
request.environ['REQUEST_METHOD'] = method
request._auth = 'Basic %s' % b64encode(
'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use .format() instead?

request._auth = 'Basic %s' % b64encode(
'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
request._auth = 'Basic %s' % b64encode(auth.encode('utf8')).decode('utf8')
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't we use .format() instead?

@@ -116,7 +116,7 @@ def _url_with_params(self, params):
# result of parse_qsl into a dict!

# Drop params to be updated, then prepend new params in order
qs_params = filter(lambda x: x[0] not in params.keys(), qs_params)
qs_params = [x for x in qs_params if x[0] not in list(params.keys())]
Copy link
Member

Choose a reason for hiding this comment

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

this should be written: qs_params = [x for x in qs_params if x[0] not in list(params)]

@davisagli
Copy link
Member

Folks, this is still a work in progress. If you want to help with that work, feel free, but otherwise please wait with the comments until it's marked ready for review.

@jaroel
Copy link
Member

jaroel commented Oct 2, 2018

Ack - I'm out 👍
I've been asked to do a review and will happily do so, but I'll wait for David's signal.

@davisagli
Copy link
Member

davisagli commented Oct 2, 2018

At this point the todo list before it's ready for review is:

  • Fix remaining test failures in Python 3 + Plone 5.2 - @davisagli
  • Clean up unnecessary if HAS_AT checks - @jaroel
  • Look into differences in docs output and figure out what to do
  • Check to see if any other changes got included that shouldn't be there

I put my name next to the one I'm working on; if someone else wants to work on one of the other items edit this comment and add your name to claim it.

@tisto
Copy link
Member

tisto commented Oct 2, 2018

@lukasgraf yeah. That sounds like a good idea. I still don't understand how those changes ended up in this branch in the first place. Maybe somebody accidentally committed the doc changes...

@tisto
Copy link
Member

tisto commented Oct 2, 2018

@davisagli yeah. That's correct. I will merge my branch into this one then to get it green...

@tisto
Copy link
Member

tisto commented Oct 2, 2018

Oh. Seems somebody already merged my fix. :)

@tisto
Copy link
Member

tisto commented Oct 2, 2018

I know @davisagli does not like this but I did a quick first review of this PR. Now I am not that afraid of having to do the review to be honest, which is good. Apart from the standard py3 stuff that I see I am wondering if there isn't a better way to make the AT dependency optional. So far what we do is to include AT-specific code via zcml conditionals. Since David also excluded those code fragments via if/else I suppose that is not sufficient when running things on Python 3.

@lukasgraf @buchi since you folks wrote the AT code, what is your opinion? Does the current way of excluding the AT-specific code via import + if/else makes sense to you? Would it be an alternative to factor out the AT-specific code into some kind of subpackage within plone.restapi? Or would it be an option to make a plone.restapi release without AT for Plone 5.2?

@pbauer we plan to drop AT support for Python 3, correct? Question is: is it worth the effort to support AT on Plone 5.2 / Python 2.7.

@hvelarde
Copy link
Member

hvelarde commented Oct 2, 2018

@tisto AT is going to be deprecated in Plone 6, not before; I see no reason to make it Python 3 compatible, but it must work on Plone 5.2 with Python 2.7.

@tisto
Copy link
Member

tisto commented Oct 2, 2018

@hvelarde we are talking about exposing AT via plone.restapi. Whatever we do with plone.restapi, it goes far beyond anything we ever promised or imagined.

@jaroel
Copy link
Member

jaroel commented Oct 3, 2018

I've cleaned out as many HAS_AT checks as I could.
The ones remaining are there so I don't have to move all AT related tests to their own package - incl the layer. We'll have to remove that when AT is gone.

@pbauer
Copy link
Member Author

pbauer commented Oct 12, 2018

AT is deprecated with Plone 5.2. It will continue to work on Python 2 with Plone 5.2 but I do not think it will still work with 6.0 unless someone else takes care of this. I would have liked to spare us the effort of supporting AT in 5.2 but then we'd have had to deprecate it in 5.1 already.

@pbauer pbauer merged commit 1d4d683 into master Oct 17, 2018
@pbauer pbauer deleted the python3 branch October 17, 2018 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants