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
Conversation
… (FYI, waitress doesn't support ssl_pem option)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. My comments are mostly stylistic suggestions.
I would prefer if you dropped the ZODB._compat dependency before merging this, but I won't care that much if you don't.
generate-sample-cert.sh
Outdated
rm sample.key sample.cert | ||
|
||
openssl req -new -x509 -nodes -sha1 -days 3650 -key sample.key > sample.crt | ||
cat sample.crt sample.key > sample.pem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's time to replace -sha1
with -sha256
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW is the .pem file still needed? I see you're configuring it to use .key and .crt separately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, sha256 definitely.
You're right, the .pem can be removed if we use "--ca-certificate sample.crt" instead of "--ca-certificate sample.pem" with wget. I can change the commands in the README.
UuBcNoW6zXoEYU6oV1Oi6hjhW1eu6PuAv4jPY754XoiNEZdZqYQqo8BFkWtDW1/C | ||
GXrtQRbMDPzD40UYB2UCQQCmJpJp+u2lHj7zuZikHIHQBNyXyoGnzgNs6XUj1Bs6 | ||
Y4vjue8w6RkRLZ1YGP+xqsngVqb9IRygyLDpEgwEnOT4 | ||
-----END RSA PRIVATE KEY----- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this is convenient, if we don't ship a sample private key, people won't accidentally use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The private key was already in the repo, the sample.pem contains both the public and private keys.
The sample certificate was committed I guess so you can test the app without having the openssl command. There is bin/testclient if you don't have wget too.
src/keas/kmi/README.txt
Outdated
>>> data="encryptioniscool"*24*1024 | ||
>>> tmp_file.write(data) | ||
>>> tmp_file.seek(0) | ||
>>> data=b"encryptioniscool"*24*1024 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as you're changing this, can add the missing spaces around =
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure
src/keas/kmi/README.txt
Outdated
>>> encrypted_file = tempfile.TemporaryFile() | ||
>>> keys.encrypt_file(key, tmp_file, encrypted_file) | ||
>>> tmp_file.close() | ||
|
||
And decrypt the file | ||
|
||
>>> decrypted_file = tempfile.TemporaryFile() | ||
>>> encrypted_file.seek(0) | ||
>>> pos =encrypted_file.seek(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A space after the =
would be nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oups, my bad.
iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16)) | ||
# bytes(bytearray(generator)) is needed for Python 2, | ||
# with Python 3 bytes(generator) works | ||
iv = bytes(bytearray((random.randint(0, 0xFF)) for i in range(16))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a cryptographer, but I think it's a good idea to use a strong RNG for IVs --> use os.urandom(16)
? That would also make the code simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah os.urandom(16) is really great! Much simpler indeed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The random here is not the random package from Python, but "from Crypto.Random import random". I'm not sure we want to change that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh dear, that's terribly misleading!
(I've lost the will to care.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(If this was written today, I'd suggest using cryptography
instead of M2Crypto.)
src/keas/kmi/persistent.py
Outdated
@@ -14,8 +14,7 @@ | |||
"""Encrypted persistent objects | |||
""" | |||
from __future__ import absolute_import | |||
import cPickle | |||
import cStringIO | |||
from ZODB._compat import BytesIO, Pickler, Unpickler |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not import from private modules of other packages (here, ZODB). Create a keas.kmi._compat
module and copy the relevant bits into it -- or just use six
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll do that.
|
||
|
||
def new_key(kmf): | ||
sys.stdout.write(kmf.generate()) | ||
os.write(sys.stdout.fileno(), kmf.generate()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interesting approach! I'd've gone with getattr(sys.stdout, 'buffer', sys.stdout).write(kmf.generate())
.
I don't have any arguments in favour of one or the other approach. sys.stdout.buffer is easier to stub in unit tests, but os.write(...fileno(), ...) is shorter. It's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did try sys.stdout.buffer first, but when I saw sys.stdout.buffer didn't work on Python 2, I searched for another solution and found this.
@@ -1,3 +1,4 @@ | |||
from __future__ import print_function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should go after the block comment, right above the __docformat__
assignment (which can probably be thrown away).
src/keas/kmi/testclient.py
Outdated
except IOError, e: | ||
print >> sys.stderr, "Could not read %s" % filename | ||
print >> sys.stderr, e | ||
return open(filename, 'rb').read() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A nice opportunity to use with open(...) as fp: return fp.read()
-- it'll avoid ResourceWarnings on Python 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point
.travis.yml
Outdated
@@ -1,6 +1,8 @@ | |||
language: python | |||
python: | |||
- 2.7 | |||
- 3.4 | |||
- 3.6 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no 3.5?
There was a problem hiding this comment.
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!
The Python 3.6 failure is about a different exception message. We usually deal with those by using a doctest renormalizer (see, e.g. zope.sqlalchemy for an example). While I believe doctest allows you to ignore the exception message if you use |
Ah right, I did actually test only with the Python 3.4 on my machine. I'll look into fixing the error on Python 3.6 with a normalizer. |
@mgedmin I think we can merge it now. FYI, I signed the zope contributor agreement. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Feel free to merge.
Tell me your PyPI username if you wish to be able to make a release.
|
||
class Unpickler(zodbpickle.pickle.Unpickler): | ||
def __init__(self, f): | ||
super(Unpickler, self).__init__(f) |
There was a problem hiding this comment.
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?
|
||
try: | ||
# XXX: why not just import BytesIO from io? | ||
from cStringIO import StringIO as BytesIO |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.)
iv = ''.join(chr(random.randint(0, 0xFF)) for i in range(16)) | ||
# bytes(bytearray(generator)) is needed for Python 2, | ||
# with Python 3 bytes(generator) works | ||
iv = bytes(bytearray((random.randint(0, 0xFF)) for i in range(16))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh dear, that's terribly misleading!
(I've lost the will to care.)
My username is vincentfretin on pypi. |
You have PyPI rights now. I would expect zest.releaser to work fine on this package. I would also install check-manifest for its zest.release hook to be doubly sure. |
Changes released as 3.2.0 |
The code now runs on both Python 2.7 and Python 3.4-3.6, the tests pass on both.
I replaced the paster server by gunicorn.
I dropped Python < 2.7 support (I removed the try except hashlib / md5)