Skip to content

Commit

Permalink
Merge pull request #8 from zopefoundation/master-python3
Browse files Browse the repository at this point in the history
Prepare for Python 2 / 3 compatibility
  • Loading branch information
Michael Howitz authored Apr 24, 2018
2 parents 343e80d + 1d238a8 commit a65e742
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 58 deletions.
4 changes: 3 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ Changelog

- Add needed dependencies in `setup.py`.

- Prepare for Python 2 / 3 compatibility [davilima6]


2.0.3 (2017-07-17)
------------------

- Document Zope version compatibility [dataflake]
- Document Zope version compatibility [dataflake]


2.0.2 (2017-02-14)
Expand Down
54 changes: 22 additions & 32 deletions Products/ExternalEditor/ExternalEditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,53 +16,44 @@

# Zope External Editor Product by Casey Duncan

from string import join # For Zope 2.3 compatibility
import types
import urllib
from AccessControl.SecurityInfo import ClassSecurityInfo
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.class_init import InitializeClass
from Acquisition import aq_inner, aq_base, aq_parent, Implicit
try:
from App.class_init import InitializeClass
except ImportError:
from App.class_init import default__class_init__ as InitializeClass
from App.Common import rfc1123_date
from AccessControl.SecurityManagement import getSecurityManager
from AccessControl.SecurityInfo import ClassSecurityInfo
from OFS import Image
try:
from webdav.Lockable import wl_isLocked
except ImportError:
# webdav module not available
def wl_isLocked(ob):
return 0
from OFS.Lockable import wl_isLocked
from six.moves import urllib
import six

from zExceptions import BadRequest
from ZPublisher.Iterators import IStreamIterator
from zope.interface import implements, Interface
HAVE_Z3_IFACE = issubclass(IStreamIterator, Interface)
from zope.interface import implementer

ExternalEditorPermission = 'Use external editor'

_callbacks = []


@implementer(IStreamIterator)
class PDataStreamIterator:
if HAVE_Z3_IFACE:
implements(IStreamIterator)
else:
__implements__ = IStreamIterator

def __init__(self, data):
self.data = data

def __iter__(self):
return self

def next(self):
def __next__(self):
# Python 3
if self.data is None:
raise StopIteration
data = self.data.data
self.data = self.data.next
self.data = next(self.data)
return data

next = __next__ # Python 2


def registerCallback(cb):
"""Register a callback to be called by the External Editor when
Expand Down Expand Up @@ -129,8 +120,8 @@ def index_html(self, REQUEST, RESPONSE, path=None):
if title is not None:
if callable(title):
title = title()
if isinstance(title, types.UnicodeType):
title = unicode.encode(title, 'utf-8')
if isinstance(title, six.text_type):
title = title.encode('utf-8')
r.append('title:%s' % title)

if hasattr(aq_base(ob), 'content_type'):
Expand Down Expand Up @@ -169,7 +160,7 @@ def index_html(self, REQUEST, RESPONSE, path=None):

# Finish metadata with an empty line.
r.append('')
metadata = join(r, '\n')
metadata = '\n'.join(r)
metadata_len = len(metadata)

# Check if we should send the file's data down the response.
Expand Down Expand Up @@ -218,10 +209,9 @@ def index_html(self, REQUEST, RESPONSE, path=None):
body = ob.read()
else:
# can't read it!
raise 'BadRequest', 'Object does not support external editing'
raise BadRequest('Object does not support external editing')

if (HAVE_Z3_IFACE and IStreamIterator.providedBy(body) or
(not HAVE_Z3_IFACE) and IStreamIterator.isImplementedBy(body)):
if IStreamIterator.providedBy(body):
# We need to manage our content-length because we're streaming.
# The content-length should have been set in the response by
# the method that returns the iterator, but we need to fix it up
Expand All @@ -233,11 +223,11 @@ def index_html(self, REQUEST, RESPONSE, path=None):
RESPONSE.write(data)
return ''

# If we reached this point, body *must* be a string. We *must*
# If we reached this point, body must be a string. We *must*
# set the headers ourselves since _write_metadata won't get
# called.
self._set_headers(RESPONSE)
return join((metadata, body), '\n')
return '\n'.join((metadata, body))

def _set_headers(self, RESPONSE):
# Using RESPONSE.setHeader('Pragma', 'no-cache') would be better, but
Expand Down Expand Up @@ -292,7 +282,7 @@ def EditLink(self, object, borrow_lock=0, skip_data=0):
if skip_data:
query['skip_data'] = 1
url = "%s/externalEdit_/%s%s%s" % (aq_parent(aq_inner(object)).absolute_url(),
urllib.quote(object.getId()),
urllib.parse.quote(object.getId()),
ext, querystr(query))
return ('<a href="%s" '
'title="Edit using external editor">'
Expand Down
2 changes: 1 addition & 1 deletion Products/ExternalEditor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from OFS.FindSupport import FindSupport
from OFS.Folder import Folder
from App.Management import Tabs
from ExternalEditor import ExternalEditor, EditLink
from Products.ExternalEditor.ExternalEditor import ExternalEditor, EditLink

# Add the icon and the edit method to the misc_ namespace

Expand Down
48 changes: 24 additions & 24 deletions Products/ExternalEditor/tests/edit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ External Editor:

>>> self.folder.manage_addFile('some-file', file='some content')

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file.zem HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: 167
Content-Type: application/x-zope-edit
Expand All @@ -38,7 +38,7 @@ External Editor:
Lock the file, should now send out the lock-token in the metadata:

>>> self.folder['some-file'].wl_clearLocks()
>>> print http(r"""
>>> print(http(r"""
... LOCK /test_folder_1_/some-file HTTP/1.1
... Content-Type: text/xml; charset="utf-8"
... Depth: 0
Expand All @@ -48,15 +48,15 @@ Lock the file, should now send out the lock-token in the metadata:
... <DAV:lockinfo xmlns:DAV="DAV:">
... <DAV:lockscope><DAV:exclusive/></DAV:lockscope>
... <DAV:locktype><DAV:write/></DAV:locktype>
... </DAV:lockinfo>""" % (user_name, user_password))
... </DAV:lockinfo>""" % (user_name, user_password)))
HTTP/1.1 200 OK
...
Lock-Token: ...

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: ...
Content-Type: application/x-zope-edit
Expand All @@ -77,10 +77,10 @@ Lock the file, should now send out the lock-token in the metadata:
If 'borrow_lock' is found in the request, then a 'borrow_lock:1' is
appended to the metadata along with the lock-token:

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file?borrow_lock=1 HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: ...
Content-Type: application/x-zope-edit
Expand All @@ -102,10 +102,10 @@ appended to the metadata along with the lock-token:
If 'skip_data' is found in the request, then the file data is **not**
appended after the metadata:

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file?skip_data=1 HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: ...
Content-Type: application/x-zope-edit
Expand All @@ -131,10 +131,10 @@ A user that is not the lock owner will not get the 'lock-token' or
>>> uf = self.folder.acl_users
>>> _ = uf.userFolderAddUser(user_name_2, user_password_2, ['Manager'], [])

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file?borrow_lock=1 HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name_2, user_password_2))
... """ % (user_name_2, user_password_2)))
HTTP/1.1 200 OK
Content-Length: 163
Content-Type: application/x-zope-edit
Expand Down Expand Up @@ -163,10 +163,10 @@ to 'application/x-zope-edit':
>>> from Products.ExternalEditor.tests.test_functional import SideEffects
>>> _ = self.folder._setObject('another-file', SideEffects('another-file', 'some content'))

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/another-file HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: 140
Content-Type: application/x-zope-edit
Expand Down Expand Up @@ -195,10 +195,10 @@ that is sent out:
>>> old_cb = _callbacks[:]
>>> registerCallback(md_callback)

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file?borrow_lock=1 HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: 191
Content-Type: application/x-zope-edit
Expand Down Expand Up @@ -227,10 +227,10 @@ REQUEST, for example the 'skip_data' parameter:
>>> old_cb = _callbacks[:]
>>> registerCallback(req_callback)

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Length: 155
Content-Type: application/x-zope-edit
Expand All @@ -257,10 +257,10 @@ the RESPONSE:
>>> old_cb = _callbacks[:]
>>> registerCallback(resp_callback)

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file HTTP/1.1
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Content-Encoding: gzip
Content-Length: 159
Expand All @@ -277,11 +277,11 @@ MSIE cache behaviour

We set the user agent at `MSIE` and look at the cache headers.

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file.zem HTTP/1.1
... User-Agent: MSIE
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Cache-Control: must-revalidate, post-check=0, pre-check=0
Content-Length: 167
Expand All @@ -302,11 +302,11 @@ We set the user agent at `MSIE` and look at the cache headers.
Because we also are IE 1.0 compliant, we try with `Microsoft Internet Explorer'
Cheers JNUT !! ;)

>>> print http(r"""
>>> print(http(r"""
... GET /test_folder_1_/externalEdit_/some-file.zem HTTP/1.1
... User-Agent: Microsoft Internet Explorer
... Authorization: Basic %s:%s
... """ % (user_name, user_password))
... """ % (user_name, user_password)))
HTTP/1.1 200 OK
Cache-Control: must-revalidate, post-check=0, pre-check=0
Content-Length: 167
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'setuptools',
'Zope >= 4.0b4',
'ZServer >= 4.0b1',
'six',
],
entry_points="""
[console_scripts]
Expand Down

0 comments on commit a65e742

Please sign in to comment.