Add Python 2 / 3 compatibility

This commit is contained in:
Philip Bauer 2018-01-25 13:04:11 +01:00
parent 1a8d2c9bdd
commit 93a227c80d
8 changed files with 41 additions and 27 deletions

View File

@ -14,7 +14,8 @@ New features:
Bug fixes: Bug fixes:
- *add item here* - Add Python 2 / 3 compatibility
[pbauer]
3.0.4 (2017-11-24) 3.0.4 (2017-11-24)

View File

@ -33,6 +33,9 @@ from zope.i18nmessageid import Message
from zope.interface import alsoProvides from zope.interface import alsoProvides
import six
COMMENT_DESCRIPTION_PLAIN_TEXT = _( COMMENT_DESCRIPTION_PLAIN_TEXT = _(
u'comment_description_plain_text', u'comment_description_plain_text',
default=u'You can add a comment by filling out the form below. ' default=u'You can add a comment by filling out the form below. '
@ -152,11 +155,11 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
if 'author_name' in data: if 'author_name' in data:
author_name = data['author_name'] author_name = data['author_name']
if isinstance(author_name, str): if isinstance(author_name, str):
author_name = unicode(author_name, 'utf-8') author_name = six.text_type(author_name, 'utf-8')
if 'author_email' in data: if 'author_email' in data:
author_email = data['author_email'] author_email = data['author_email']
if isinstance(author_email, str): if isinstance(author_email, str):
author_email = unicode(author_email, 'utf-8') author_email = six.text_type(author_email, 'utf-8')
# Set comment author properties for anonymous users or members # Set comment author properties for anonymous users or members
portal_membership = getToolByName(context, 'portal_membership') portal_membership = getToolByName(context, 'portal_membership')
@ -171,10 +174,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
if not fullname or fullname == '': if not fullname or fullname == '':
fullname = member.getUserName() fullname = member.getUserName()
elif isinstance(fullname, str): elif isinstance(fullname, str):
fullname = unicode(fullname, 'utf-8') fullname = six.text_type(fullname, 'utf-8')
author_name = fullname author_name = fullname
if email and isinstance(email, str): if email and isinstance(email, str):
email = unicode(email, 'utf-8') email = six.text_type(email, 'utf-8')
# XXX: according to IComment interface author_email must not be # XXX: according to IComment interface author_email must not be
# set for logged in users, cite: # set for logged in users, cite:
# 'for anonymous comments only, set to None for logged in comments' # 'for anonymous comments only, set to None for logged in comments'
@ -427,7 +430,7 @@ class CommentsViewlet(ViewletBase):
""" """
if self.get_replies(workflow_actions) is not None: if self.get_replies(workflow_actions) is not None:
try: try:
self.get_replies(workflow_actions).next() next(self.get_replies(workflow_actions))
return True return True
except StopIteration: # pragma: no cover except StopIteration: # pragma: no cover
pass pass

View File

@ -40,6 +40,9 @@ from zope.interface import implementer
import logging import logging
import six
COMMENT_TITLE = _( COMMENT_TITLE = _(
u'comment_title', u'comment_title',
default=u'${author_name} on ${content}', default=u'${author_name} on ${content}',
@ -122,7 +125,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
@property @property
def __name__(self): def __name__(self):
return self.comment_id and unicode(self.comment_id) or None return self.comment_id and six.text_type(self.comment_id) or None
@property @property
def id(self): def id(self):
@ -147,7 +150,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
text = self.text text = self.text
if text is None: if text is None:
return '' return ''
if isinstance(text, unicode): if isinstance(text, six.text_type):
text = text.encode('utf8') text = text.encode('utf8')
transform = transforms.convertTo( transform = transforms.convertTo(
targetMimetype, targetMimetype,
@ -238,7 +241,7 @@ def notify_content_object_deleted(obj, event):
if IAnnotatable.providedBy(obj): if IAnnotatable.providedBy(obj):
conversation = IConversation(obj) conversation = IConversation(obj)
while conversation: while conversation:
del conversation[conversation.keys()[0]] del conversation[list(conversation.keys())[0]]
def notify_comment_added(obj, event): def notify_comment_added(obj, event):
@ -427,7 +430,7 @@ def notify_moderator(obj, event):
# Send email # Send email
try: try:
mail_host.send(message, mto, sender, subject, charset='utf-8') mail_host.send(message, mto, sender, subject, charset='utf-8')
except SMTPException, e: except SMTPException as e:
logger.error('SMTP exception (%s) while trying to send an ' + logger.error('SMTP exception (%s) while trying to send an ' +
'email notification to the comment moderator ' + 'email notification to the comment moderator ' +
'(from %s to %s, message: %s)', '(from %s to %s, message: %s)',

View File

@ -40,6 +40,9 @@ from zope.lifecycleevent import ObjectRemovedEvent
import time import time
import six
@implementer(IConversation, IHideFromBreadcrumbs) @implementer(IConversation, IHideFromBreadcrumbs)
class Conversation(Traversable, Persistent, Explicit): class Conversation(Traversable, Persistent, Explicit):
"""A conversation is a container for all comments on a content object. """A conversation is a container for all comments on a content object.
@ -110,7 +113,7 @@ class Conversation(Traversable, Persistent, Explicit):
def getComments(self, start=0, size=None): def getComments(self, start=0, size=None):
"""Get unthreaded comments """Get unthreaded comments
""" """
count = 0l count = 0
for comment in self._comments.values(min=start): for comment in self._comments.values(min=start):
# Yield the acquisition wrapped comment # Yield the acquisition wrapped comment
yield self[comment.id] yield self[comment.id]
@ -138,7 +141,7 @@ class Conversation(Traversable, Persistent, Explicit):
# Find top level threads # Find top level threads
comments = self._children.get(root, None) comments = self._children.get(root, None)
if comments is not None: if comments is not None:
count = 0l count = 0
for comment_id in comments.keys(min=start): for comment_id in comments.keys(min=start):
# Abort if we have found all the threads we want # Abort if we have found all the threads we want
@ -274,14 +277,14 @@ class Conversation(Traversable, Persistent, Explicit):
return [v.__of__(self) for v in self._comments.values()] return [v.__of__(self) for v in self._comments.values()]
def iterkeys(self): def iterkeys(self):
return self._comments.iterkeys() return six.iterkeys(self._comments)
def itervalues(self): def itervalues(self):
for v in self._comments.itervalues(): for v in six.itervalues(self._comments):
yield v.__of__(self) yield v.__of__(self)
def iteritems(self): def iteritems(self):
for k, v in self._comments.iteritems(): for k, v in six.iteritems(self._comments):
yield (k, v.__of__(self),) yield (k, v.__of__(self),)
def allowedContentTypes(self): def allowedContentTypes(self):
@ -334,7 +337,7 @@ class ConversationReplies(object):
def __init__(self, context): def __init__(self, context):
self.conversation = context self.conversation = context
self.comment_id = 0l self.comment_id = 0
def addComment(self, comment): def addComment(self, comment):
comment.in_reply_to = None comment.in_reply_to = None

View File

@ -565,8 +565,8 @@ class TestCommentsViewlet(unittest.TestCase):
replies = self.viewlet.get_replies() replies = self.viewlet.get_replies()
self.assertEqual(len(tuple(replies)), 2) self.assertEqual(len(tuple(replies)), 2)
replies = self.viewlet.get_replies() replies = self.viewlet.get_replies()
replies.next() next(replies)
replies.next() next(replies)
self.assertRaises(StopIteration, replies.next) self.assertRaises(StopIteration, replies.next)
def test_get_replies_on_non_annotatable_object(self): def test_get_replies_on_non_annotatable_object(self):
@ -593,7 +593,7 @@ class TestCommentsViewlet(unittest.TestCase):
('comment_review_workflow,') ('comment_review_workflow,')
) )
# Check if workflow actions are available # Check if workflow actions are available
reply = self.viewlet.get_replies(workflow_actions=True).next() reply = next(self.viewlet.get_replies(workflow_actions=True))
self.assertTrue('actions' in reply) self.assertTrue('actions' in reply)
self.assertEqual( self.assertEqual(
reply['actions'][0]['id'], reply['actions'][0]['id'],

View File

@ -22,6 +22,9 @@ from zope.component import queryUtility
import unittest import unittest
import six
try: try:
from plone.dexterity.interfaces import IDexterityContent from plone.dexterity.interfaces import IDexterityContent
DEXTERITY = True DEXTERITY = True
@ -383,17 +386,17 @@ class ConversationTest(unittest.TestCase):
self.assertTrue(comment2 in conversation.values()) self.assertTrue(comment2 in conversation.values())
# check if comment ids are in iterkeys # check if comment ids are in iterkeys
self.assertTrue(new_id1 in conversation.iterkeys()) self.assertTrue(new_id1 in six.iterkeys(conversation))
self.assertTrue(new_id2 in conversation.iterkeys()) self.assertTrue(new_id2 in six.iterkeys(conversation))
self.assertFalse(123 in conversation.iterkeys()) self.assertFalse(123 in six.iterkeys(conversation))
# check if comment objects are in itervalues # check if comment objects are in itervalues
self.assertTrue(comment1 in conversation.itervalues()) self.assertTrue(comment1 in six.itervalues(conversation))
self.assertTrue(comment2 in conversation.itervalues()) self.assertTrue(comment2 in six.itervalues(conversation))
# check if iteritems returns (key, comment object) pairs # check if iteritems returns (key, comment object) pairs
self.assertTrue((new_id1, comment1) in conversation.iteritems()) self.assertTrue((new_id1, comment1) in six.iteritems(conversation))
self.assertTrue((new_id2, comment2) in conversation.iteritems()) self.assertTrue((new_id2, comment2) in six.iteritems(conversation))
# TODO test acquisition wrapping # TODO test acquisition wrapping
# self.assertTrue(aq_base(aq_parent(comment1)) is conversation) # self.assertTrue(aq_base(aq_parent(comment1)) is conversation)

View File

@ -156,7 +156,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
# Make sure that the two comments have been deleted # Make sure that the two comments have been deleted
self.assertEqual(len(self.conversation.objectIds()), 1) self.assertEqual(len(self.conversation.objectIds()), 1)
comment = self.conversation.getComments().next() comment = next(self.conversation.getComments())
self.assertTrue(comment) self.assertTrue(comment)
self.assertEqual(comment, self.comment2) self.assertEqual(comment, self.comment2)

View File

@ -16,6 +16,7 @@ install_requires = [
'plone.registry', 'plone.registry',
'plone.z3cform', 'plone.z3cform',
'Products.CMFPlone', 'Products.CMFPlone',
'six',
'ZODB3', 'ZODB3',
'zope.interface', 'zope.interface',
'zope.component', 'zope.component',