[Checkins] SVN: zope.password/trunk/ Support Py 3.3, add tox setup and manifest.
Stephen Richter
cvs-admin at zope.org
Thu Feb 21 19:45:04 UTC 2013
Log message for revision 129588:
Support Py 3.3, add tox setup and manifest.
Changed:
_U zope.password/trunk/
U zope.password/trunk/CHANGES.txt
A zope.password/trunk/MANIFEST.in
U zope.password/trunk/bootstrap.py
U zope.password/trunk/buildout.cfg
U zope.password/trunk/setup.py
U zope.password/trunk/src/zope/password/interfaces.py
U zope.password/trunk/src/zope/password/legacy.py
U zope.password/trunk/src/zope/password/password.py
U zope.password/trunk/src/zope/password/testing.py
U zope.password/trunk/src/zope/password/tests/test_password.py
U zope.password/trunk/src/zope/password/tests/test_zpasswd.py
U zope.password/trunk/src/zope/password/zpasswd.py
A zope.password/trunk/tox.ini
-=-
Property changes on: zope.password/trunk
___________________________________________________________________
Modified: svn:ignore
- bin
build
dist
lib
develop-eggs
eggs
parts
.installed.cfg
coverage
+ .tox
bin
build
dist
lib
develop-eggs
eggs
parts
.installed.cfg
coverage
Modified: zope.password/trunk/CHANGES.txt
===================================================================
--- zope.password/trunk/CHANGES.txt 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/CHANGES.txt 2013-02-21 19:45:04 UTC (rev 129588)
@@ -5,13 +5,15 @@
4.0.0 (unreleased)
------------------
+- Added support for Python 3.3
+
- Replaced deprecated ``zope.interface.implements`` usage with equivalent
``zope.interface.implementer`` decorator.
- Dropped support for Python 2.4 and 2.5.
-- Add a new IMatchingPasswordManager interface with a 'match' method, which
- returns True if a given password hash was encdoded with the scheme
+- Add a new ``IMatchingPasswordManager`` interface with a 'match' method,
+ which returns True if a given password hash was encdoded with the scheme
implemented by the specific manager. All managers in this package implement
this interface.
Added: zope.password/trunk/MANIFEST.in
===================================================================
--- zope.password/trunk/MANIFEST.in (rev 0)
+++ zope.password/trunk/MANIFEST.in 2013-02-21 19:45:04 UTC (rev 129588)
@@ -0,0 +1,9 @@
+include *.rst
+include *.txt
+include *.py
+include buildout.cfg
+include tox.ini
+
+recursive-include src *
+
+global-exclude *.pyc
Modified: zope.password/trunk/bootstrap.py
===================================================================
--- zope.password/trunk/bootstrap.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/bootstrap.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -18,33 +18,148 @@
use the -c option to specify an alternate configuration file.
"""
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile
+from optparse import OptionParser
tmpeggs = tempfile.mkdtemp()
-ez = {}
-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
- ).read() in ez
-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
-import pkg_resources
+Bootstraps a buildout-based project.
-cmd = 'from setuptools.command.easy_install import main; main()'
-if sys.platform == 'win32':
- cmd = '"%s"' % cmd # work around spawn lamosity on windows
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
-ws = pkg_resources.working_set
-assert os.spawnle(
- os.P_WAIT, sys.executable, sys.executable,
- '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
- dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse('setuptools')).location
- ),
- ) == 0
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
+
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true", default=False,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+parser.add_option("-f", "--find-links",
+ help=("Specify a URL to search for buildout releases"))
+
+
+options, args = parser.parse_args()
+
+######################################################################
+# load/install distribute
+
+to_reload = False
+try:
+ import pkg_resources, setuptools
+ if not hasattr(pkg_resources, '_distribute'):
+ to_reload = True
+ raise ImportError
+except ImportError:
+ ez = {}
+
+ try:
+ from urllib.request import urlopen
+ except ImportError:
+ from urllib2 import urlopen
+
+ exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez)
+ setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True)
+ ez['use_setuptools'](**setup_args)
+
+ if to_reload:
+ reload(pkg_resources)
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+######################################################################
+# Install buildout
+
+ws = pkg_resources.working_set
+
+cmd = [sys.executable, '-c',
+ 'from setuptools.command.easy_install import main; main()',
+ '-mZqNxd', tmpeggs]
+
+find_links = os.environ.get(
+ 'bootstrap-testing-find-links',
+ options.find_links or
+ ('http://downloads.buildout.org/'
+ if options.accept_buildout_test_releases else None)
+ )
+if find_links:
+ cmd.extend(['-f', find_links])
+
+distribute_path = ws.find(
+ pkg_resources.Requirement.parse('distribute')).location
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[distribute_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0:
+ raise Exception(
+ "Failed to execute command:\n%s",
+ repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
+
ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
+ws.require(requirement)
import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+
+if not [a for a in args if '=' not in a]:
+ args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+ args[0:0] = ['-c', options.config_file]
+
+zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
Modified: zope.password/trunk/buildout.cfg
===================================================================
--- zope.password/trunk/buildout.cfg 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/buildout.cfg 2013-02-21 19:45:04 UTC (rev 129588)
@@ -20,7 +20,6 @@
interpreter = python
[zpasswd]
-recipe = z3c.recipe.dev:script
+recipe = zc.recipe.egg
eggs = zope.password
-module = zope.password.zpasswd
-method = main
+scripts = zpasswd
Modified: zope.password/trunk/setup.py
===================================================================
--- zope.password/trunk/setup.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/setup.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -15,6 +15,20 @@
"""
from setuptools import setup, find_packages
+def alltests():
+ import os
+ import sys
+ import unittest
+ # use the zope.testrunner machinery to find all the
+ # test suites we've put under ourselves
+ import zope.testrunner.find
+ import zope.testrunner.options
+ here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
+ args = sys.argv[:]
+ defaults = ["--test-path", here]
+ options = zope.testrunner.options.get_options(args, defaults)
+ suites = list(zope.testrunner.find.find_suites(options))
+ return unittest.TestSuite(suites)
setup(name='zope.password',
version='4.0.0dev',
@@ -37,6 +51,9 @@
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: Implementation :: CPython',
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
@@ -45,7 +62,7 @@
packages=find_packages('src'),
package_dir = {'': 'src'},
extras_require=dict(vocabulary=['zope.schema'],
- test=['zope.schema'],
+ test=['zope.schema', 'zope.testing'],
),
namespace_packages=['zope'],
install_requires=['setuptools',
@@ -53,6 +70,16 @@
'zope.configuration',
'zope.interface',
],
+ tests_require = [
+ 'zope.schema',
+ 'zope.testing',
+ 'zope.testrunner',
+ ],
+ test_suite = '__main__.alltests',
include_package_data = True,
zip_safe = False,
+ entry_points="""
+ [console_scripts]
+ zpasswd = zope.password.zpasswd:main
+ """,
)
Modified: zope.password/trunk/src/zope/password/interfaces.py
===================================================================
--- zope.password/trunk/src/zope/password/interfaces.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/interfaces.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -19,10 +19,14 @@
"""Password manager"""
def encodePassword(password):
- """Return encoded data for the given password"""
+ """Return encoded data for the given password
+ The encoded password is a bytes string.
+ """
+
def checkPassword(encoded_password, password):
- """Does the given encoded data coincide with the given password"""
+ """Does the given encoded data coincide with the given password
+ """
class IMatchingPasswordManager(IPasswordManager):
"""Password manager with hash matching support"""
@@ -31,5 +35,5 @@
"""
Returns True when the given data was encoded with the scheme
implemented by this password manager.
-
+
"""
Modified: zope.password/trunk/src/zope/password/legacy.py
===================================================================
--- zope.password/trunk/src/zope/password/legacy.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/legacy.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -14,7 +14,7 @@
"""Legacy password managers, using now-outdated, insecure methods for hashing
"""
__docformat__ = 'restructuredtext'
-
+import sys
from codecs import getencoder
try:
@@ -29,16 +29,24 @@
_encoder = getencoder("utf-8")
+PY2 = sys.version_info[0] == 2
+try:
+ unicode
+except NameError:
+ # Py3: Define unicode.
+ unicode = str
+
+
if crypt is not None:
@implementer(IMatchingPasswordManager)
class CryptPasswordManager(object):
"""Crypt password manager.
-
- Implements a UNIX crypt(3) hashing scheme. Note that crypt is
+
+ Implements a UNIX crypt(3) hashing scheme. Note that crypt is
considered far inferior to more modern schemes such as SSHA hashing,
and only uses the first 8 characters of a password.
-
+
>>> from zope.interface.verify import verifyObject
>>> manager = CryptPasswordManager()
@@ -58,7 +66,7 @@
against an 8 character password plus suffix always matches. Our test
password (including utf-8 encoding) is exactly 8 characters long, and
thus affixing 'wrong' to it tests as a correct password::
-
+
>>> manager.checkPassword(encoded, password + u"wrong")
True
@@ -67,7 +75,7 @@
>>> manager.checkPassword(encoded, 'completely wrong')
False
- Using the `openssl passwd` command-line utility to encode ``secret``,
+ Using the `openssl passwd` command-line utility to encode ``secret``,
we get ``erz50QD3gv4Dw`` as seeded hash.
Our password manager generates the same value when seeded with the
@@ -88,7 +96,7 @@
>>> manager.encodePassword(password) != manager.encodePassword(password)
True
- The manager only claims to implement CRYPT encodings, anything not
+ The manager only claims to implement CRYPT encodings, anything not
starting with the string {CRYPT} returns False::
>>> manager.match('{MD5}someotherhash')
@@ -103,10 +111,13 @@
"abcdefghijklmnopqrstuvwxyz"
"0123456789./")
salt = choice(choices) + choice(choices)
- return '{CRYPT}%s' % crypt(_encoder(password)[0], salt)
+ if PY2:
+ # Py3: Python 2 can only handle ASCII for crypt.
+ password = _encoder(password)[0]
+ return '{CRYPT}%s' % crypt(password, salt)
def checkPassword(self, encoded_password, password):
- return encoded_password == self.encodePassword(password,
+ return encoded_password == self.encodePassword(password,
encoded_password[7:9])
def match(self, encoded_password):
@@ -139,10 +150,10 @@
False
Using the password 'PHP & Information Security' should result in the
- hash ``379693e271cd3bd6``, according to
+ hash ``379693e271cd3bd6``, according to
http://phpsec.org/articles/2005/password-hashing.html
- Our password manager generates the same value when seeded with the, so we
+ Our password manager generates the same value when seeded with the, so we
can be sure, our output is compatible with MySQL versions before 4.1::
>>> password = 'PHP & Information Security'
@@ -155,7 +166,7 @@
>>> manager.checkPassword(encoded, password + u"wrong")
False
- The manager only claims to implement MYSQL encodings, anything not
+ The manager only claims to implement MYSQL encodings, anything not
starting with the string {MYSQL} returns False::
>>> manager.match('{MD5}someotherhash')
@@ -165,21 +176,28 @@
def encodePassword(self, password):
- nr = 1345345333L
+ nr = 1345345333
add = 7
- nr2 = 0x12345671L
+ nr2 = 0x12345671
for i in _encoder(password)[0]:
- if i == ' ' or i == '\t':
+ if PY2:
+ # In Python 2 bytes iterate over single-char strings.
+ i = ord(i)
+ if i == ord(b' ') or i == ord(b'\t'):
continue
- nr ^= (((nr & 63) + add) * ord(i)) + (nr << 8)
+ nr ^= (((nr & 63) + add) * i) + (nr << 8)
nr2 += (nr2 << 8) ^ nr
- add += ord(i)
- r0 = nr & ((1L << 31) - 1L)
- r1 = nr2 & ((1L << 31) - 1L)
- return "{MYSQL}%08lx%08lx" % (r0, r1)
+ add += i
+ r0 = nr & ((1 << 31) - 1)
+ r1 = nr2 & ((1 << 31) - 1)
+ return ("{MYSQL}%08lx%08lx" % (r0, r1)).encode()
def checkPassword(self, encoded_password, password):
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
return encoded_password == self.encodePassword(password)
def match(self, encoded_password):
- return encoded_password.startswith('{MYSQL}')
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ return encoded_password.startswith(b'{MYSQL}')
Modified: zope.password/trunk/src/zope/password/password.py
===================================================================
--- zope.password/trunk/src/zope/password/password.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/password.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -19,20 +19,20 @@
from base64 import standard_b64decode
from base64 import urlsafe_b64decode
from binascii import a2b_hex
+from hashlib import md5, sha1
from os import urandom
from codecs import getencoder
-try:
- from hashlib import md5, sha1
-except ImportError:
- # Python 2.4
- from md5 import new as md5
- from sha import new as sha1
from zope.interface import implementer
from zope.password.interfaces import IMatchingPasswordManager
_encoder = getencoder("utf-8")
+try:
+ unicode
+except NameError:
+ # Py3: Define unicode.
+ unicode = str
@implementer(IMatchingPasswordManager)
class PlainTextPasswordManager(object):
@@ -46,8 +46,8 @@
>>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
>>> encoded = manager.encodePassword(password)
- >>> encoded
- u'right \u0410'
+ >>> encoded == password.encode('utf-8')
+ True
>>> manager.checkPassword(encoded, password)
True
>>> manager.checkPassword(encoded, password + u"wrong")
@@ -65,6 +65,8 @@
def encodePassword(self, password):
+ if isinstance(password, unicode):
+ password = password.encode('utf-8')
return password
def checkPassword(self, encoded_password, password):
@@ -138,7 +140,7 @@
>>> passwd = u'foobar\u2211' # sigma-sign.
>>> manager.checkPassword(manager.encodePassword(passwd), passwd)
True
- >>> manager.checkPassword(unicode(manager.encodePassword(passwd)), passwd)
+ >>> manager.checkPassword(manager.encodePassword(passwd).decode(), passwd)
True
The manager only claims to implement SSHA encodings, anything not starting
@@ -160,16 +162,20 @@
def encodePassword(self, password, salt=None):
if salt is None:
salt = urandom(4)
+ elif isinstance(salt, unicode):
+ salt = salt.encode('utf-8')
hash = sha1(_encoder(password)[0])
hash.update(salt)
- return '{SSHA}' + standard_b64encode(hash.digest() + salt)
+ return b'{SSHA}' + standard_b64encode(hash.digest() + salt)
def checkPassword(self, encoded_password, password):
# standard_b64decode() cannot handle unicode input string. We
# encode to ascii. This is safe as the encoded_password string
# should not contain non-ascii characters anyway.
- encoded_password = encoded_password.encode('ascii')[6:]
- if '_' in encoded_password or '-' in encoded_password:
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ encoded_password = encoded_password[6:]
+ if b'_' in encoded_password or b'-' in encoded_password:
# Encoded using old urlsafe_b64encode, re-encode
byte_string = urlsafe_b64decode(encoded_password)
encoded_password = standard_b64encode(byte_string)
@@ -179,7 +185,9 @@
return encoded_password == self.encodePassword(password, salt)[6:]
def match(self, encoded_password):
- return encoded_password.startswith('{SSHA}')
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ return encoded_password.startswith(b'{SSHA}')
class SMD5PasswordManager(PlainTextPasswordManager):
@@ -238,7 +246,7 @@
>>> passwd = u'foobar\u2211' # sigma-sign.
>>> manager.checkPassword(manager.encodePassword(passwd), passwd)
True
- >>> manager.checkPassword(unicode(manager.encodePassword(passwd)), passwd)
+ >>> manager.checkPassword(manager.encodePassword(passwd).decode(), passwd)
True
The manager only claims to implement SMD5 encodings, anything not starting
@@ -252,21 +260,23 @@
def encodePassword(self, password, salt=None):
if salt is None:
salt = urandom(4)
+ elif isinstance(salt, unicode):
+ salt = salt.encode('utf-8')
hash = md5(_encoder(password)[0])
hash.update(salt)
- return '{SMD5}' + standard_b64encode(hash.digest() + salt)
+ return b'{SMD5}' + standard_b64encode(hash.digest() + salt)
def checkPassword(self, encoded_password, password):
- # standard_b64decode() cannot handle unicode input string. We
- # encode to ascii. This is safe as the encoded_password string
- # should not contain non-ascii characters anyway.
- encoded_password = encoded_password.encode('ascii')[6:]
- byte_string = standard_b64decode(encoded_password)
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ byte_string = standard_b64decode(encoded_password[6:])
salt = byte_string[16:]
- return encoded_password == self.encodePassword(password, salt)[6:]
+ return encoded_password == self.encodePassword(password, salt)
def match(self, encoded_password):
- return encoded_password.startswith('{SMD5}')
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ return encoded_password.startswith(b'{SMD5}')
class MD5PasswordManager(PlainTextPasswordManager):
@@ -302,7 +312,7 @@
>>> passwd = u'foobar\u2211' # sigma-sign.
>>> manager.checkPassword(manager.encodePassword(passwd), passwd)
True
- >>> manager.checkPassword(unicode(manager.encodePassword(passwd)), passwd)
+ >>> manager.checkPassword(manager.encodePassword(passwd).decode(), passwd)
True
A previous version of this manager also created a cosmetic salt, added
@@ -326,18 +336,22 @@
def encodePassword(self, password, salt=None):
# The salt argument only exists for backwards compatibility and is
# ignored on purpose.
- return '{MD5}%s' % standard_b64encode(
+ return b'{MD5}' + standard_b64encode(
md5(_encoder(password)[0]).digest())
def checkPassword(self, encoded_password, password):
- encoded = encoded_password[encoded_password.find('}') + 1:]
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ encoded = encoded_password[encoded_password.find(b'}') + 1:]
if len(encoded) > 24:
# Backwards compatible, hexencoded md5 and bogus salt
encoded = standard_b64encode(a2b_hex(encoded[-32:]))
return encoded == self.encodePassword(password)[5:]
def match(self, encoded_password):
- return encoded_password.startswith('{MD5}')
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
+ return encoded_password.startswith(b'{MD5}')
class SHA1PasswordManager(PlainTextPasswordManager):
@@ -373,7 +387,7 @@
>>> passwd = u'foobar\u2211' # sigma-sign.
>>> manager.checkPassword(manager.encodePassword(passwd), passwd)
True
- >>> manager.checkPassword(unicode(manager.encodePassword(passwd)), passwd)
+ >>> manager.checkPassword(manager.encodePassword(passwd).decode(), passwd)
True
A previous version of this manager also created a cosmetic salt, added
@@ -410,12 +424,14 @@
def encodePassword(self, password, salt=None):
# The salt argument only exists for backwards compatibility and is
# ignored on purpose.
- return '{SHA}%s' % standard_b64encode(
+ return b'{SHA}' + standard_b64encode(
sha1(_encoder(password)[0]).digest())
def checkPassword(self, encoded_password, password):
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
if self.match(encoded_password):
- encoded = encoded_password[encoded_password.find('}') + 1:]
+ encoded = encoded_password[encoded_password.find(b'}') + 1:]
if len(encoded) > 28:
# Backwards compatible, hexencoded sha1 and bogus salt
encoded = standard_b64encode(a2b_hex(encoded[-40:]))
@@ -425,9 +441,11 @@
return encoded_password == self.encodePassword(password)[5:]
def match(self, encoded_password):
+ if isinstance(encoded_password, unicode):
+ encoded_password = encoded_password.encode('ascii')
return (
- encoded_password.startswith('{SHA}') or
- encoded_password.startswith('{SHA1}'))
+ encoded_password.startswith(b'{SHA}') or
+ encoded_password.startswith(b'{SHA1}'))
# Simple registry
Modified: zope.password/trunk/src/zope/password/testing.py
===================================================================
--- zope.password/trunk/src/zope/password/testing.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/testing.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -35,7 +35,7 @@
def setUpPasswordManagers():
"""Helper function for setting up password manager utilities for tests
-
+
>>> from zope.component import getUtility
>>> setUpPasswordManagers()
@@ -81,7 +81,7 @@
>>> CryptPasswordManager is None or 'Crypt' in voc
True
-
+
"""
provideUtility(PlainTextPasswordManager(), IMatchingPasswordManager,
'Plain Text')
@@ -90,7 +90,7 @@
provideUtility(SMD5PasswordManager(), IMatchingPasswordManager, 'SMD5')
provideUtility(SHA1PasswordManager(), IMatchingPasswordManager, 'SHA1')
provideUtility(MySQLPasswordManager(), IMatchingPasswordManager, 'MySQL')
-
+
if CryptPasswordManager is not None:
provideUtility(CryptPasswordManager, IMatchingPasswordManager, 'Crypt')
Modified: zope.password/trunk/src/zope/password/tests/test_password.py
===================================================================
--- zope.password/trunk/src/zope/password/tests/test_password.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/tests/test_password.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -14,13 +14,23 @@
"""Password Managers Tests
"""
import doctest
+import re
import unittest
+from zope.testing import renormalizing
+checker = renormalizing.RENormalizing([
+ # Python 3 bytes add a "b".
+ (re.compile("b('.*?')"),
+ r"\1"),
+ (re.compile('b(".*?")'),
+ r"\1"),
+ ])
+
def test_suite():
return unittest.TestSuite((
- doctest.DocTestSuite('zope.password.password'),
- doctest.DocTestSuite('zope.password.legacy'),
+ doctest.DocTestSuite('zope.password.password', checker=checker),
+ doctest.DocTestSuite('zope.password.legacy', checker=checker),
doctest.DocTestSuite(
'zope.password.testing',
- optionflags=doctest.ELLIPSIS),
+ optionflags=doctest.ELLIPSIS, checker=checker),
))
Modified: zope.password/trunk/src/zope/password/tests/test_zpasswd.py
===================================================================
--- zope.password/trunk/src/zope/password/tests/test_zpasswd.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/tests/test_zpasswd.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -17,15 +17,20 @@
import os
import sys
import unittest, doctest
-from StringIO import StringIO
+try:
+ from StringIO import StringIO
+except ImportError:
+ # Py3: StringIO moved to io.
+ from io import StringIO
+
from zope.password import password, zpasswd
class TestBase(unittest.TestCase):
def setUp(self):
# Create a minimal site.zcml file
open('testsite.zcml', 'wb').write(
- '<configure xmlns="http://namespaces.zope.org/zope"/>\n'
+ b'<configure xmlns="http://namespaces.zope.org/zope"/>\n'
)
self.stdout = StringIO()
self.stderr = StringIO()
@@ -55,7 +60,7 @@
def check_stdout_content(self, args):
try:
options = self.parse_args(args)
- except SystemExit, e:
+ except SystemExit as e:
self.assertEqual(e.code, 0)
self.assert_(self.stdout.getvalue())
self.failIf(self.stderr.getvalue())
@@ -130,7 +135,8 @@
def test_principal_information(self):
options = self.createOptions()
app = ControlledInputApplication(options,
- ["id", "title", "login", "1", "passwd", "passwd", "description"])
+ ["id", u"title", u"login", u"1",
+ u"passwd", u"passwd", u"description"])
app.process()
self.failUnless(not self.stderr.getvalue())
self.failUnless(app.all_input_consumed())
Modified: zope.password/trunk/src/zope/password/zpasswd.py
===================================================================
--- zope.password/trunk/src/zope/password/zpasswd.py 2013-02-21 18:33:31 UTC (rev 129587)
+++ zope.password/trunk/src/zope/password/zpasswd.py 2013-02-21 19:45:04 UTC (rev 129588)
@@ -13,6 +13,7 @@
##############################################################################
"""Implementation of the zpasswd script.
"""
+from __future__ import print_function
import optparse
import os
import pkg_resources
@@ -27,7 +28,7 @@
argv = sys.argv
try:
options = parse_args(argv)
- except SystemExit, e:
+ except SystemExit as e:
if e.code:
return 2
else:
@@ -37,14 +38,14 @@
return app.process()
except KeyboardInterrupt:
return 1
- except SystemExit, e:
+ except SystemExit as e:
return e.code
class Principal(object):
"""Principal.
- >>> principal = Principal("id", "title", "login", "password")
- >>> print principal
+ >>> principal = Principal("id", u"title", u"login", b"password")
+ >>> print(principal)
<principal
id="id"
title="title"
@@ -52,9 +53,9 @@
password="password"
/>
- >>> principal = Principal("id", "title", "login", "password",
- ... "description", "SHA1")
- >>> print principal
+ >>> principal = Principal("id", u"title", u"login", b"password",
+ ... u"description", "SHA1")
+ >>> print(principal)
<principal
id="id"
title="title"
@@ -80,7 +81,7 @@
' id=%s' % quoteattr(self.id),
' title=%s' % quoteattr(self.title),
' login=%s' % quoteattr(self.login),
- ' password=%s' % quoteattr(self.password)
+ ' password=%s' % quoteattr(self.password.decode())
]
if self.description:
lines.append(' description=%s' % quoteattr(self.description))
@@ -157,9 +158,9 @@
principal = self.get_principal()
if destination is sys.stdout:
- print self.title
- print >>destination, principal
- print
+ print(self.title)
+ print(principal, file=destination)
+ print()
return 0
@@ -183,7 +184,7 @@
while True:
value = self.read_input_line(prompt).strip()
if not value and error:
- print >>sys.stderr, error
+ print(error, file=sys.stderr)
continue
return value
@@ -194,7 +195,7 @@
managers = self.options.managers
for i, (name, manager) in enumerate(managers):
- print "% i. %s" % (i + 1, name)
+ print("% i. %s" % (i + 1, name))
if name == 'SSHA':
default = i
print
@@ -210,8 +211,8 @@
if index > 0 and index <= len(managers):
index -= 1
break
- print >>sys.stderr, "You must select a password manager"
- print "%s password manager selected" % managers[index][0]
+ print("You must select a password manager", file=sys.stderr)
+ print("%s password manager selected" % managers[index][0])
return managers[index]
def get_password(self):
@@ -219,15 +220,15 @@
while True:
password = self.read_password("Password: ")
if not password:
- print >>sys.stderr, "Password may not be empty"
+ print("Password may not be empty", file=sys.stderr)
continue
if password != password.strip() or password.split() != [password]:
- print >>sys.stderr, "Password may not contain spaces"
+ print("Password may not contain spaces", file=sys.stderr)
continue
break
again = self.read_password("Verify password: ")
if again != password:
- print >>sys.stderr, "Password not verified!"
+ print("Password not verified!", file=sys.stderr)
sys.exit(1)
return password
@@ -235,7 +236,7 @@
if self.need_blank_line:
print
self.need_blank_line = False
- print message
+ print(message)
def get_password_managers(config_path=None):
if not config_path:
@@ -245,7 +246,7 @@
from zope.component import getUtilitiesFor
from zope.password.interfaces import IPasswordManager
- print "Loading configuration..."
+ print("Loading configuration...")
config = xmlconfig.file(config_path)
managers = []
for name, manager in getUtilitiesFor(IPasswordManager):
Added: zope.password/trunk/tox.ini
===================================================================
--- zope.password/trunk/tox.ini (rev 0)
+++ zope.password/trunk/tox.ini 2013-02-21 19:45:04 UTC (rev 129588)
@@ -0,0 +1,17 @@
+[tox]
+envlist =
+ py26,py27,py33
+
+[testenv]
+commands =
+ python setup.py test -q
+# without explicit deps, setup.py test will download a bunch of eggs into $PWD
+# (and it seems I can't use zope.dottedname[testing] here, so forget DRY)
+deps =
+ zope.component
+ zope.configuration
+ zope.interface
+ zope.schema
+ zope.testing
+ zope.testrunner
+
More information about the checkins
mailing list