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

Port to Python 3 #2

Merged
merged 11 commits into from
May 15, 2017
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ language: python
python:
- 2.7
- 3.4
- 3.5
- 3.6
Copy link
Member

Choose a reason for hiding this comment

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

Why no 3.5?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can add it.
I didn't put it because I didn't have a python 3.5 environment on my machine, so I didn't test it myself. But travis is here for that!

install:
- python bootstrap.py
Expand Down
4 changes: 2 additions & 2 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ To get started do::
The server will come up on port 8080. You can create a new key encrypting key
using::

$ wget https://localhost:8080/new -O kek.dat --ca-certificate sample.pem \
$ wget https://localhost:8080/new -O kek.dat --ca-certificate sample.crt \
--post-data=""

or, if you want a more convenient tool::
Expand All @@ -21,7 +21,7 @@ The data encryption key can now be retrieved by posting the KEK to another
URL::

$ wget https://localhost:8080/key --header 'Content-Type: text/plain' \
--post-file kek.dat -O datakey.dat --ca-certificate sample.pem
--post-file kek.dat -O datakey.dat --ca-certificate sample.crt

or ::

Expand Down
3 changes: 1 addition & 2 deletions generate-sample-cert.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/bin/sh
openssl genrsa 1024 > sample.key
openssl req -new -x509 -nodes -sha1 -days 3650 -key sample.key > sample.crt
cat sample.crt sample.key > sample.pem
openssl req -new -x509 -nodes -sha256 -days 3650 -key sample.key > sample.crt
31 changes: 0 additions & 31 deletions sample.pem

This file was deleted.

8 changes: 8 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ def read(*rnames):
'Intended Audience :: Developers',
'License :: OSI Approved :: Zope Public License',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP'],
Expand All @@ -62,6 +69,7 @@ def read(*rnames):
'pyramid',
'pyramid_zcml',
'setuptools',
'six',
'transaction',
'zope.interface',
'zope.schema',
Expand Down
4 changes: 2 additions & 2 deletions src/keas/kmi/README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ We can also encrypt data given by a file descriptor

>>> import tempfile
>>> tmp_file = tempfile.TemporaryFile()
>>> data=b"encryptioniscool"*24*1024
>>> data = b"encryptioniscool"*24*1024
>>> pos = tmp_file.write(data)
>>> pos = tmp_file.seek(0)
>>> encrypted_file = tempfile.TemporaryFile()
Expand All @@ -103,7 +103,7 @@ We can also encrypt data given by a file descriptor
And decrypt the file

>>> decrypted_file = tempfile.TemporaryFile()
>>> pos =encrypted_file.seek(0)
>>> pos = encrypted_file.seek(0)
>>> keys.decrypt_file(key, encrypted_file, decrypted_file)
>>> encrypted_file.close()

Expand Down
59 changes: 59 additions & 0 deletions src/keas/kmi/_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
##############################################################################
#
# Copyright (c) 2013 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
import sys
from six import PY3

# This code was copied from ZODB/_compat.py

if not PY3:
# Python 2.x
# PyPy's cPickle doesn't have noload, and noload is broken in Python 2.7,
# so we need zodbpickle.
# Get the fastest working version we can (PyPy has no fastpickle)
try:
import zodbpickle.fastpickle as cPickle
except ImportError:
import zodbpickle.pickle as cPickle
Pickler = cPickle.Pickler
Unpickler = cPickle.Unpickler
else:
# Python 3.x: can't use stdlib's pickle because
# http://bugs.python.org/issue6784
import zodbpickle.pickle

class Pickler(zodbpickle.pickle.Pickler):
def __init__(self, f, protocol=None):
super(Pickler, self).__init__(f, protocol)

class Unpickler(zodbpickle.pickle.Unpickler):
def __init__(self, f):
super(Unpickler, self).__init__(f)
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand why these __init__ methods are necessary. They don't seem to be doing anything, except calling the base version?


# Py3: Python 3 doesn't allow assignments to find_global,
# instead, find_class can be overridden

find_global = None

def find_class(self, modulename, name):
if self.find_global is None:
return super(Unpickler, self).find_class(modulename, name)
return self.find_global(modulename, name)


try:
# XXX: why not just import BytesIO from io?
from cStringIO import StringIO as BytesIO
Copy link
Member

Choose a reason for hiding this comment

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

I think io.BytesIO is noticeably slower on 2.7. I haven't personally benchmarked, and I don't remember why I think so.

It's probably mostly because old code used cStringIO and if we keep using the same thing, we're sure nothing unexpected will break.

Copy link
Member

Choose a reason for hiding this comment

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

I know the io package was slower on 2.6, because it was written in Python. But in 2.7 it was moved to C, so maybe that's not an issue anymore.

Updated module: The io library has been upgraded to the version shipped with Python 3.1. For 3.1, the I/O library was entirely rewritten in C and is 2 to 20 times faster depending on the task being performed.

(Using cStringIO on Python 2 but BytesIO on Python 3 is confusing and could be a source of bugs, IMO, because they accept different things. cStringIO will happily allow you to mix unicode and bytes, but BytesIO won't.)

except ImportError:
# Python 3.x
from io import BytesIO
1 change: 0 additions & 1 deletion src/keas/kmi/facility.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@

from hashlib import md5

__docformat__ = "reStructuredText"

logger = logging.getLogger('kmi')

Expand Down
3 changes: 0 additions & 3 deletions src/keas/kmi/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
from zope.interface.common import mapping


__docformat__ = "reStructuredText"


class IEncryptionService(zope.interface.Interface):
"""Utility providing encryption mechanism"""

Expand Down
1 change: 0 additions & 1 deletion src/keas/kmi/keyholder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
##############################################################################
"""Simple Key Holder
"""
__docformat__ = "reStructuredText"
from zope.interface import implementer
from keas.kmi.interfaces import IKeyHolder

Expand Down
2 changes: 1 addition & 1 deletion src/keas/kmi/persistent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""Encrypted persistent objects
"""
from __future__ import absolute_import
from ZODB._compat import BytesIO, Pickler, Unpickler
from keas.kmi._compat import BytesIO, Pickler, Unpickler
import persistent
import persistent.wref
from zope.component import getUtility
Expand Down
2 changes: 1 addition & 1 deletion src/keas/kmi/persistent.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ error:
>>> pwd.password
Traceback (most recent call last):
...
ValueError: need more than 1 value to unpack
ValueError: not enough values to unpack (expected 2, got 1)

But we can apply the conversion step:

Expand Down
9 changes: 5 additions & 4 deletions src/keas/kmi/testclient.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from __future__ import print_function
##############################################################################
#
# Copyright (c) 2008 Zope Foundation and Contributors.
Expand All @@ -14,7 +13,7 @@
##############################################################################
"""Test client to access the KMI server API.
"""
__docformat__ = "reStructuredText"
from __future__ import print_function

import os
import sys
Expand Down Expand Up @@ -45,7 +44,8 @@ def new_key(kmf):

def read_kek(kekfile):
try:
return open(kekfile, 'rb').read()
with open(kekfile, 'rb') as fp:
return fp.read()
except IOError as e:
print("Could not read key encrypting key from %s" % kekfile, file=sys.stderr)
print(e, file=sys.stderr)
Expand All @@ -57,7 +57,8 @@ def read_data(filename=None):
return sys.stdin.read()
else:
try:
return open(filename, 'rb').read()
with open(filename, 'rb') as fp:
return fp.read()
except IOError as e:
print("Could not read %s" % filename, file=sys.stderr)
print(e, file=sys.stderr)
Expand Down
10 changes: 9 additions & 1 deletion src/keas/kmi/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
"""Test Setup
"""
import doctest
import re
import tempfile
import transaction
import unittest

from zope.app.testing import setup
from zope.component import provideUtility
from zope.testing.renormalizing import RENormalizing

from keas.kmi.testing import TestingKeyManagementFacility
from keas.kmi.interfaces import IKeyManagementFacility
Expand All @@ -39,6 +41,11 @@ def tearDownPersistent(test):


def test_suite():
checker = RENormalizing([
# fix doctest for ValueError exception on Python < 3.6
(re.compile(r"ValueError: need more than 1 value to unpack"),
"ValueError: not enough values to unpack (expected 2, got 1)")
])
return unittest.TestSuite([
doctest.DocFileSuite(
'README.txt',
Expand All @@ -49,5 +56,6 @@ def test_suite():
doctest.DocFileSuite(
'persistent.txt',
setUp=setUpPersistent, tearDown=tearDownPersistent,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
checker=checker),
])