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

Python 3 support #75

Merged
merged 21 commits into from
Oct 17, 2018
Merged

Python 3 support #75

merged 21 commits into from
Oct 17, 2018

Conversation

pbauer
Copy link
Member

@pbauer pbauer commented Jun 22, 2018

No description provided.

@coveralls
Copy link

coveralls commented Jun 22, 2018

Coverage Status

Coverage decreased (-0.02%) to 97.731% when pulling 8f5c6c9 on python3 into 0078eda on master.

@@ -41,7 +41,7 @@ def setUpZope(self, app, configurationContext):
class InternalServerErrorService(Service):

def __call__(self):
from urllib2 import HTTPError
from six.moves.urllib.error import HTTPError
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 declare the dependency on six in setup.py

@pbauer
Copy link
Member Author

pbauer commented Jun 28, 2018

Tests in py3 are: 96 tests, 8 failures, 0 errors, 0 skipped.

@@ -41,8 +41,9 @@ 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' % (TEST_USER_NAME, TEST_USER_PASSWORD))
auth = '%s:%s' % (TEST_USER_NAME, TEST_USER_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?

'%s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD))
auth = '%s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD)
b64auth = b64encode(auth.encode('utf8'))
request._auth = 'Basic %s' % b64auth.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?

@@ -32,8 +32,9 @@ 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?

'%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
auth = '%s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD)
b64auth = b64encode(auth.encode('utf8'))
request._auth = 'Basic %s' % b64auth.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?

@hvelarde
Copy link
Member

this seems to be almost ready now:

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

------------------------------------
Your code has been rated at 10.00/10

@lukasgraf
Copy link
Member

lukasgraf commented Jul 13, 2018

Regarding the remaining 8 failures on Plone 5.2 / py3.cfg:

These aren't Python 3 failures as such, but come from the difference between ZServer.ZPublisher and ZPublisher.WSGIPublisher.

7 of the 8 failures are because status 401 doesn't get returned where it's expected:

AssertionError: The following assertions failed:

Request:  ('/', 'POST', ())
Expected: 401
Got:      404
...

This is because in WSGIPublisher, the response._unauthorized() gets triggered before the exception view is called. In ZPublisher this happens the other way round, and plone.rest gets a change to prevent PAS from issuing a challenge and triggering a redirect to the login form.


The remaining failure is caused by WSGIPublisher normalizing HTTP exceptions. This leads to the last actual exception (sys.exc_info()) being different from the exception that the error view gets, and causing plone.rest to fail on this check:

AssertionError: 'ERROR: Another exception happened before we could render the traceback.' is not an instance of <class 'list'>

@pbauer
Copy link
Member Author

pbauer commented Jul 16, 2018

@davisagli or @tschorr could one of you have a look at this? I'm notoriously bad when it comes to understanding the various layers of exception-handling.

@tschorr
Copy link
Contributor

tschorr commented Jul 19, 2018

The remaining failure is caused by WSGIPublisher normalizing HTTP exceptions.

Always when I see x-wsgiorg.throw_errors in code (as in the 2 lines above the Unathorized handling), I wonder wether this is used anywhere outside of Zope. The specification for this was created in 2006 and is still in proposed state ...

Maybe get rid of x-wsgiorg.throw_errors altogether?

@tschorr
Copy link
Contributor

tschorr commented Jul 19, 2018

Running bin/test -s plone.rest with zopefoundation/Zope#294 yields 3 failures and 1 error:

Failure in test test_401_unauthorized (plone.rest.tests.test_error_handling.TestErrorHandling)
Failure in test test_404_not_found (plone.rest.tests.test_error_handling.TestErrorHandling)
Failure in test test_500_internal_server_error (plone.rest.tests.test_error_handling.TestErrorHandling)

all fail with:

AssertionError: 'text/html;charset=utf-8' != 'application/json'
- text/html;charset=utf-8
+ application/json
 : When sending a GET request with Accept: application/json the server should respond with sending back application/json.

and then there's

Error in test test_500_traceback_only_for_manager_users (plone.rest.tests.test_error_handling.TestErrorHandling)
Traceback (most recent call last):
  File "/home/thomas/.pyenv/versions/3.6.5/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/home/thomas/.pyenv/versions/3.6.5/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/home/thomas/devel/plone/buildout.coredev/src/plone.rest/src/plone/rest/tests/test_error_handling.py", line 107, in test_500_traceback_only_for_manager_users
    self.assertNotIn(u'traceback', response.json())
  File "/home/thomas/.buildout/eggs/cp36m/requests-2.19.1-py3.6.egg/requests/models.py", line 896, in json
    return complexjson.loads(self.text, **kwargs)
  File "/home/thomas/.buildout/eggs/cp36m/simplejson-3.16.0-py3.6-linux-x86_64.egg/simplejson/__init__.py", line 518, in loads
    return _default_decoder.decode(s)
  File "/home/thomas/.buildout/eggs/cp36m/simplejson-3.16.0-py3.6-linux-x86_64.egg/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/home/thomas/.buildout/eggs/cp36m/simplejson-3.16.0-py3.6-linux-x86_64.egg/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.errors.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

@davisagli
Copy link
Member

davisagli commented Jul 19, 2018

@tschorr that's because you disabled exception view rendering, which is how plone.rest turns exceptions into JSON responses.

I would need to take a closer look at how to fix the problems that @lukasgraf pointed out, but getting rid of exception view rendering is not it.

tschorr added a commit to zopefoundation/Zope that referenced this pull request Jul 20, 2018
@tschorr
Copy link
Contributor

tschorr commented Jul 20, 2018

This is because in WSGIPublisher, the response._unauthorized() gets triggered before the exception view is called. In ZPublisher this happens the other way round, and plone.rest gets a change to prevent PAS from issuing a challenge and triggering a redirect to the login form.

@lukasgraf I have reversed the order according to your proposal in https://github.com/zopefoundation/Zope/tree/py3_fix_wsgi_unauthorized and confirm this fixes 7 tests. Tests in Zope all pass with this modification.

@tschorr
Copy link
Contributor

tschorr commented Jul 20, 2018

Jenkins looks slightly better using py3_fix_wsgi_unauthorized: https://jenkins.plone.org/view/PLIPs/job/plip-py3/582

@tschorr
Copy link
Contributor

tschorr commented Jul 20, 2018

Checks for this PR pass now maybe because only Python 2.7 is tested with Travis. I still have the one failing test mentioned by @lukasgraf ("Another exception ...") using Python 3.6.

@tisto
Copy link
Member

tisto commented Jul 20, 2018

@tschorr feel free to add Python 3 to the Travis configuration.

@lukasgraf
Copy link
Member

@tschorr thanks for looking into this!

Just to clarify, I'm not necessarily proposing that the order in WSGIPublisher needs to be changed - I just noticed that this is the underlying cause of these failures in plone.rest. I left some feedback in my comment on #304.

pbauer pushed a commit to zopefoundation/Zope that referenced this pull request Sep 14, 2018
davisagli pushed a commit to zopefoundation/Zope that referenced this pull request Oct 2, 2018
src/plone/rest/errors.py Outdated Show resolved Hide resolved
@frapell
Copy link
Member

frapell commented Oct 4, 2018

@pbauer I see this is hitting plone/plone.protect#74 even though it is using python 2.7.14 (see latest travis https://travis-ci.org/plone/plone.rest/jobs/436770003)

Do we need a new release of plone.protect with the latest changes for tests to pass?

@jensens jensens merged commit c30de1e into master Oct 17, 2018
@jensens jensens deleted the python3 branch October 17, 2018 09:44
@tisto
Copy link
Member

tisto commented Nov 8, 2018

@jensens FYI: you merged this PR even though the Travis build failed. Please keep in mind that plone.rest and plone.restapi are used outside of Plone and for older Plone versions. It is just not sufficient if coredev tests pass.

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.

10 participants