diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2012-01-18 16:37:53 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2012-01-18 16:37:53 -0500 |
| commit | 8cc56a03f05fac2d5717394ced5f53cf71b17814 (patch) | |
| tree | 69e8f5907537cc93558c16d141720560533d7a6c | |
| parent | ffb343b6bb0ba8b6015f19493347c7aae65739fd (diff) | |
| download | passlib-8cc56a03f05fac2d5717394ced5f53cf71b17814.tar.gz | |
cleanups to utils
| -rw-r--r-- | passlib/apps.py | 2 | ||||
| -rw-r--r-- | passlib/hosts.py | 4 | ||||
| -rw-r--r-- | passlib/tests/test_utils_handlers.py | 4 | ||||
| -rw-r--r-- | passlib/utils/__init__.py | 150 | ||||
| -rw-r--r-- | passlib/utils/compat.py | 15 | ||||
| -rw-r--r-- | passlib/utils/md4.py | 4 |
6 files changed, 82 insertions, 97 deletions
diff --git a/passlib/apps.py b/passlib/apps.py index be16090..8040b46 100644 --- a/passlib/apps.py +++ b/passlib/apps.py @@ -9,7 +9,7 @@ from itertools import chain #libs from passlib import hash from passlib.context import LazyCryptContext -from passlib.utils.compat import sys_bits +from passlib.utils import sys_bits #pkg #local __all__ = [ diff --git a/passlib/hosts.py b/passlib/hosts.py index 4ef2bca..38b3bf6 100644 --- a/passlib/hosts.py +++ b/passlib/hosts.py @@ -8,7 +8,7 @@ from warnings import warn #pkg from passlib.context import LazyCryptContext from passlib.registry import get_crypt_handler -from passlib.utils import os_crypt, unix_crypt_schemes +from passlib.utils import has_os_crypt, unix_crypt_schemes #local __all__ = [ "linux_context", "linux2_context", @@ -56,7 +56,7 @@ netbsd_context = LazyCryptContext([ "bcrypt", "sha1_crypt", "md5_crypt", "bsdi_c #========================================================= #current host #========================================================= -if os_crypt: +if has_os_crypt: #NOTE: this is basically mimicing the output of os crypt(), #except that it uses passlib's (usually stronger) defaults settings, #and can be introspected and used much more flexibly. diff --git a/passlib/tests/test_utils_handlers.py b/passlib/tests/test_utils_handlers.py index 3f4fb60..838d016 100644 --- a/passlib/tests/test_utils_handlers.py +++ b/passlib/tests/test_utils_handlers.py @@ -14,8 +14,8 @@ from passlib.hash import ldap_md5, sha256_crypt from passlib.registry import _unload_handler_name as unload_handler_name, \ register_crypt_handler, get_crypt_handler from passlib.utils import rng, getrandstr, handlers as uh, bytes, b, \ - to_native_str, to_unicode, MissingBackendError -from passlib.utils.compat import unicode, JYTHON + to_native_str, to_unicode, MissingBackendError, JYTHON +from passlib.utils.compat import unicode from passlib.tests.utils import HandlerCase, TestCase, catch_warnings, \ dummy_handler_in_registry from passlib.utils.compat import u diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py index 6a6409b..0f53a09 100644 --- a/passlib/utils/__init__.py +++ b/passlib/utils/__init__.py @@ -1,13 +1,13 @@ -"""passlib utility functions""" -#================================================================================= +"""passlib.utils -- helpers for writing password hashes""" +#============================================================================= #imports -#================================================================================= +#============================================================================= #core from base64 import b64encode, b64decode from codecs import lookup as _lookup_codec from functools import update_wrapper import logging; log = logging.getLogger(__name__) -from math import log as logb +import math import os import sys import random @@ -17,16 +17,17 @@ import unicodedata from warnings import warn #site #pkg -from passlib.utils.compat import irange, PY3, sys_bits, unicode, bytes, u, b, \ - _add_doc +from passlib.utils.compat import irange, PY3, unicode, bytes, u, b, _add_doc #local __all__ = [ # constants + 'PYPY', + 'JYTHON', 'sys_bits', 'unix_crypt_schemes', 'rounds_cost_values', - #decorators + # decorators "classproperty", ## "deprecated_function", ## "relocated_function", @@ -35,17 +36,20 @@ __all__ = [ #byte compat aliases 'bytes', - # string manipulation + # unicode helpers 'consteq', 'saslprep', - #byte manipulation + # bytes helpers "xor_bytes", + "render_bytes", - #bytes<->unicode + # encoding helpers + 'is_same_codec', + 'is_ascii_safe', 'to_bytes', 'to_unicode', - 'is_same_codec', + 'to_native_str', # base64 helpers "BASE64_CHARS", "HASH64_CHARS", "BCRYPT_CHARS", "AB64_CHARS", @@ -73,6 +77,13 @@ __all__ = [ # constants #================================================================================= +# Python VM identification +PYPY = hasattr(sys, "pypy_version_info") +JYTHON = sys.platform.startswith('java') + +# bitsize of system architecture (32 or 64) +sys_bits = int(math.log(sys.maxsize if PY3 else sys.maxint, 2) + 1.5) + # list of hashes supported by os.crypt() on at least one OS. unix_crypt_schemes = [ "sha512_crypt", "sha256_crypt", @@ -231,9 +242,9 @@ def relocated_function(target, msg=None, name=None, deprecated=None, mod=None, ## def __func__(self): ## "py3 compatible alias" -#================================================================================= -#string helpers -#================================================================================= +#============================================================================= +# unicode helpers +#============================================================================= ujoin = _UEMPTY.join def consteq(left, right): @@ -421,7 +432,7 @@ def saslprep(source, errname="value"): return data #========================================================== -#bytes helpers +# bytes helpers #========================================================== #helpers for joining / extracting elements @@ -483,12 +494,11 @@ else: if PY3: def xor_bytes(left, right): - "perform bitwise-xor of two byte-strings" return bytes(l ^ r for l, r in zip(left, right)) else: def xor_bytes(left, right): - "perform bitwise-xor of two byte-strings" return bjoin(chr(ord(l) ^ ord(r)) for l, r in zip(left, right)) +_add_doc(xor_bytes, "perform bitwise-xor of two byte strings") def render_bytes(source, *args): """helper for using formatting operator with bytes. @@ -498,22 +508,18 @@ def render_bytes(source, *args): this function is an attempt to provide a replacement that will work uniformly under python 2 & 3. - it converts everything to unicode (including bytes arguments), - then encodes the result to latin-1. + it converts everything to unicode (decode bytes instances as latin-1), + performs the required formatting, then encodes the result to latin-1. + + calling ``render_bytes(source, *args)`` should function the same as + ``source % args`` under python 2. """ if isinstance(source, bytes): source = source.decode("latin-1") - def adapt(arg): - if isinstance(arg, bytes): - return arg.decode("latin-1") - return arg - result = source % tuple(adapt(arg) for arg in args) + result = source % tuple(arg.decode("latin-1") if isinstance(arg, bytes) + else arg for arg in args) return result.encode("latin-1") -#================================================================================= -#numeric helpers -#================================================================================= - # NOTE: deprecating bytes<->int in favor of just using struct module. @deprecated_function(deprecated="1.6", removed="1.8") @@ -533,19 +539,18 @@ def int_to_bytes(value, count): for s in irange(8*count-8,-8,-8) ) -#========================================================== -# bytes <-> unicode conversion helpers -#========================================================== - +#============================================================================= +# encoding helpers +#============================================================================= def is_same_codec(left, right): - "check if two codecs names are aliases for same codec" + "check if two codec names are aliases for same codec" if left == right: return True if not (left and right): return False return _lookup_codec(left).name == _lookup_codec(right).name -_B80 = 128 if PY3 else b('\x80') +_B80 = b('\x80')[0] _U80 = u('\x80') def is_ascii_safe(source): "check if source (bytes or unicode) contains only 7-bit ascii" @@ -553,70 +558,65 @@ def is_ascii_safe(source): return all(c < r for c in source) def to_bytes(source, encoding="utf-8", source_encoding=None, errname="value"): - """helper to encoding unicode -> bytes + """helper to normalize input to bytes. - this function takes in a ``source`` string. - if unicode, encodes it using the specified ``encoding``. - if bytes, returns unchanged - unless ``source_encoding`` - is specified, in which case the bytes are transcoded - if and only if the source encoding doesn't match - the desired encoding. - all other types result in a :exc:`TypeError`. + :arg source: + Source bytes/unicode to process. - :arg source: source bytes/unicode to process - :arg encoding: target character encoding or ``None``. - :param source_encoding: optional source encoding - :param errname: optional name of variable/noun to reference when raising errors + :arg encoding: + Target encoding (defaults to ``"utf-8"``). - :raises TypeError: if unicode encountered but ``encoding=None`` specified; - or if source is not unicode or bytes. + :param source_encoding: + Source encoding (if known), used for transcoding. - :returns: bytes object + :param errname: + Optional name of variable/noun to reference when raising errors - .. note:: + :raises TypeError: if source is not unicode or bytes. - if ``encoding`` is set to ``None``, then unicode strings - will be rejected, and only byte strings will be allowed through. + :returns: + * unicode strings will be encoded using *encoding*, and returned. + * if *source_encoding* is not specified, byte strings will be + returned unchanged. + * if *source_encoding* is specified, byte strings will be transcoded + to *encoding*. """ if isinstance(source, bytes): - if source_encoding and encoding and \ - not is_same_codec(source_encoding, encoding): + if source_encoding and not is_same_codec(source_encoding, encoding): return source.decode(source_encoding).encode(encoding) else: return source - elif not encoding: - raise TypeError("%s must be bytes, not %s" % (errname, type(source))) elif isinstance(source, unicode): return source.encode(encoding) - elif source_encoding: - raise TypeError("%s must be unicode or %s-encoded bytes, not %s" % - (errname, source_encoding, type(source))) else: - raise TypeError("%s must be unicode or bytes, not %s" % (errname, type(source))) + raise TypeError("%s must be unicode or bytes, not %s" % (errname, + type(source))) def to_unicode(source, source_encoding="utf-8", errname="value"): - """take in unicode or bytes, return unicode + """helper to normalize input to unicode. + + :arg source: + source bytes/unicode to process. - if bytes provided, decodes using specified encoding. - leaves unicode alone. + :arg source_encoding: + encoding to use when decoding bytes instances. - :raises TypeError: if source is not unicode or bytes. + :param errname: + optional name of variable/noun to reference when raising errors. - :arg source: source bytes/unicode to process - :arg source_encoding: encoding to use when decoding bytes instances - :param errname: optional name of variable/noun to reference when raising errors + :raises TypeError: if source is not unicode or bytes. - :returns: unicode object + :returns: + * returns unicode strings unchanged. + * returns bytes strings decoded using *source_encoding* """ if isinstance(source, unicode): return source - elif not source_encoding: - raise TypeError("%s must be unicode, not %s" % (errname, type(source))) elif isinstance(source, bytes): return source.decode(source_encoding) else: - raise TypeError("%s must be unicode or %s-encoded bytes, not %s" % - (errname, source_encoding, type(source))) + raise TypeError("%s must be unicode or bytes, not %s" % (errname, + type(source))) if PY3: def to_native_str(source, encoding="utf-8", errname="value"): @@ -638,10 +638,10 @@ else: (errname, type(source))) _add_doc(to_native_str, - """take in unicode or bytes, return native string + """take in unicode or bytes, return native string. python 2: encodes unicode using specified encoding, leaves bytes alone. - python 3: decodes bytes using specified encoding, leaves unicode alone. + python 3: leaves unicode alone, decodes bytes using specified encoding. :raises TypeError: if source is not unicode or bytes. @@ -1208,8 +1208,10 @@ try: from crypt import crypt as os_crypt except ImportError: #pragma: no cover safe_os_crypt = os_crypt = None + has_os_crypt = False else: # NOTE: see docstring below as to why we're wrapping os_crypt() + has_os_crypt = True if PY3: def safe_os_crypt(secret, hash): if isinstance(secret, bytes): diff --git a/passlib/utils/compat.py b/passlib/utils/compat.py index bd39a5b..5b7750c 100644 --- a/passlib/utils/compat.py +++ b/passlib/utils/compat.py @@ -28,21 +28,6 @@ __all__ = [ ] #============================================================================= -# host/vm configuration info -#============================================================================= -from math import log as logb -if PY3: - sys_bits = int(logb(sys.maxsize,2)+1.5) -else: - sys_bits = int(logb(sys.maxint,2)+1.5) -del logb -assert sys_bits in (32,64), "unexpected system bitsize: %r" % (sys_bits,) - -# VM identification -PYPY = hasattr(sys, "pypy_version_info") -JYTHON = sys.platform.startswith('java') - -#============================================================================= # lazy import aliases #============================================================================= if PY3: diff --git a/passlib/utils/md4.py b/passlib/utils/md4.py index 435f98e..df3be70 100644 --- a/passlib/utils/md4.py +++ b/passlib/utils/md4.py @@ -237,8 +237,8 @@ _builtin_md4 = md4 #========================================================================= #check if hashlib provides accelarated md4 #========================================================================= -from passlib.utils.compat import PYPY import hashlib +from passlib.utils import PYPY def _has_native_md4(): try: @@ -262,8 +262,6 @@ if _has_native_md4(): def md4(content=None): "wrapper for hashlib.new('md4')" return hashlib.new('md4', content or b('')) -else: - del hashlib #========================================================================= #eof |
