diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2011-12-06 15:37:12 -0500 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2011-12-06 15:37:12 -0500 |
| commit | e2f085dd5606c4c1547803cfcbddd5796009f50f (patch) | |
| tree | f9e25ef137a8a4a7f9308f69ed80cd4671e31a82 /passlib | |
| parent | 44292a37537d62a399bc6c73b26948454d624cb0 (diff) | |
| download | passlib-e2f085dd5606c4c1547803cfcbddd5796009f50f.tar.gz | |
added compat.aliased lazy-loading module, aliases for BytesIO/StringIO
Diffstat (limited to 'passlib')
| -rw-r--r-- | passlib/context.py | 63 | ||||
| -rw-r--r-- | passlib/utils/__init__.py | 1 | ||||
| -rw-r--r-- | passlib/utils/_blowfish/__init__.py | 11 | ||||
| -rw-r--r-- | passlib/utils/compat.py | 52 | ||||
| -rw-r--r-- | passlib/utils/pbkdf2.py | 7 |
5 files changed, 84 insertions, 50 deletions
diff --git a/passlib/context.py b/passlib/context.py index e944480..ca02a1e 100644 --- a/passlib/context.py +++ b/passlib/context.py @@ -3,14 +3,7 @@ #imports #========================================================= from __future__ import with_statement -from passlib.utils.compat import PY3, PY_MIN_32 #core -from cStringIO import StringIO -if PY_MIN_32: - #Py3.2 removed old ConfigParser, put SafeConfigParser in it's place - from ConfigParser import ConfigParser as SafeConfigParser -else: - from ConfigParser import SafeConfigParser import inspect import re import hashlib @@ -29,7 +22,9 @@ except ImportError: from passlib.registry import get_crypt_handler, _unload_handler_name from passlib.utils import to_bytes, to_unicode, bytes, Undef, \ is_crypt_handler, splitcomma, rng -from passlib.utils.compat import is_mapping, iteritems, int_types +from passlib.utils.compat import is_mapping, iteritems, int_types, \ + PY3, PY_MIN_32 +from passlib.utils.compat.aliases import SafeConfigParser, StringIO, BytesIO #pkg #local __all__ = [ @@ -180,22 +175,22 @@ class CryptPolicy(object): # # encoding issues are handled under py2 via to_bytes(), # which ensures everything is utf-8 internally. - - # Py2k # - if encoding == "utf-8": - #we want utf-8 anyways, so just load file in raw mode. + if PY3: + # for python 3, provide a unicode stream, + # so policy object's keys will be native str type (unicode). + with open(path, "rt", encoding=encoding) as stream: + return cls._from_stream(stream, section, path) + elif encoding == "utf-8": + # for python 2, provide utf-8 stream, + # so policy object's keys will be native str type (utf-8 bytes) with open(path, "rb") as stream: return cls._from_stream(stream, section, path) else: - #kinda hacked - load whole file, transcode, and parse. - with open(path, "rb") as stream: - source = stream.read() - source = source.decode(encoding).encode("utf-8") - return cls._from_stream(StringIO(source), section, path) - # Py3k # - #with open(path, "r", encoding=encoding) as stream: - # return cls._from_stream(stream, section, path) - # end Py3k # + # for python 2, transcode to utf-8 stream, + # so policy object's keys will be native str type (utf-8 bytes) + with open(path, "rb") as fh: + stream = BytesIO(source.decode(encoding).encode("utf-8")) + return cls._from_stream(stream, section, path) @classmethod def from_string(cls, source, section="passlib", encoding="utf-8"): @@ -211,13 +206,13 @@ class CryptPolicy(object): # so we parse as bytes under py2, and unicode under py3. # to handle encoding issues under py2, we use # "to_bytes()" to transcode to utf-8 as needed. - - # Py2k # - source = to_bytes(source, "utf-8", source_encoding=encoding, errname="source") - # Py3k # - #source = to_unicode(source, encoding, errname="source") - # end Py3k # - return cls._from_stream(StringIO(source), section, "<???>") + if PY3: + source = to_unicode(source, encoding, errname="source") + return cls._from_stream(StringIO(source), section, "<???>") + else: + source = to_bytes(source, "utf-8", source_encoding=encoding, + errname="source") + return cls._from_stream(BytesIO(source), section, "<???>") @classmethod def _from_stream(cls, stream, section, filename=None): @@ -657,15 +652,15 @@ class CryptPolicy(object): def to_string(self, section="passlib", encoding=None): "render to INI string; inverse of from_string() constructor" - buf = StringIO() + buf = StringIO() if PY3 else BytesIO() self.to_file(buf, section) out = buf.getvalue() - # Py2k # - out = out.decode("utf-8") - # end Py2k # + if not PY3: + out = out.decode("utf-8") if encoding: - out = out.encode(encoding) - return out + return out.encode(encoding) + else: + return out ##def to_path(self, path, section="passlib", update=False): ## "write to INI file" diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py index 40a53b9..e8be491 100644 --- a/passlib/utils/__init__.py +++ b/passlib/utils/__init__.py @@ -5,7 +5,6 @@ #core from base64 import b64encode, b64decode from codecs import lookup as _lookup_codec -from cStringIO import StringIO ##from functools import update_wrapper from hashlib import sha256 import logging; log = logging.getLogger(__name__) diff --git a/passlib/utils/_blowfish/__init__.py b/passlib/utils/_blowfish/__init__.py index a1f3695..dff1ca5 100644 --- a/passlib/utils/_blowfish/__init__.py +++ b/passlib/utils/_blowfish/__init__.py @@ -51,11 +51,12 @@ released under the BSD license:: #imports #========================================================= #core -from cStringIO import StringIO from itertools import chain import struct #pkg -from passlib.utils import rng, getrandbytes, bytes, bord, b +from passlib.utils import rng, getrandbytes, bytes, bord +from passlib.utils.compat import b +from passlib.utils.compat.aliases import BytesIO from passlib.utils._blowfish.unrolled import BlowfishEngine #local __all__ = [ @@ -81,7 +82,7 @@ digest_struct = struct.Struct(">6I") #========================================================= # Table for Base64 encoding -CHARS = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +CHARS = b("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") CHARSIDX = dict( (c, i) for i, c in enumerate(CHARS)) def encode_base64(d): @@ -98,7 +99,7 @@ def encode_base64(d): d = d.encode("utf-8") #ensure ord() returns something w/in 0..255 - rs = StringIO() + rs = BytesIO() write = rs.write dlen = len(d) didx = 0 @@ -144,7 +145,7 @@ def decode_base64(s): :raises ValueError: if invalid values are passed in """ - rs = StringIO() + rs = BytesIO() write = rs.write slen = len(s) sidx = 0 diff --git a/passlib/utils/compat.py b/passlib/utils/compat.py index 44e9302..96a7ae0 100644 --- a/passlib/utils/compat.py +++ b/passlib/utils/compat.py @@ -29,6 +29,52 @@ del logb assert sys_bits in (32,64), "unexpected system bitsize: %r" % (sys_bits,) #============================================================================= +# lazy import aliases +#============================================================================= +if PY3: + _aliases = dict( + BytesIO="io.BytesIO", + StringIO="io.StringIO", + SafeConfigParser="configparser.SafeConfigParser", + ) + if PY_MIN_32: + # py32 renamed this, removing old ConfigParser + _aliases["SafeConfigParser"] = "configparser.ConfigParser" +else: + _aliases = dict( + BytesIO="cStringIO.StringIO", + StringIO="StringIO.StringIO", + SafeConfigParser="ConfigParser.SafeConfigParser", + ) + +from types import ModuleType +class _AliasedModule(ModuleType): + "fake module that does lazy importing of attributes" + + def __init__(self, name, **source): + ModuleType.__init__(self, name) + self._source = source + + def __getattr__(self, attr): + source = self._source + if attr in source: + modname, modattr = source[attr].rsplit(".",1) + mod = __import__(modname, fromlist=[modattr], level=0) + value = getattr(mod, modattr) + setattr(self, attr, value) + return value + return types.ModuleType.__getattr__(self, attr) + + def __dir__(self): + attrs = set(dir(self.__class__)) + attrs.update(self.__dict__) + attrs.update(self._source) + return list(attrs) + +aliases = _AliasedModule(__name__ + ".aliases", **_aliases) +sys.modules[aliases.__name__] = aliases + +#============================================================================= # typing #============================================================================= def is_mapping(obj): @@ -59,6 +105,7 @@ if PY3: unicode = str __all__.append("unicode") # string_types = (str,) + else: def u(s): return s.decode("unicode_escape") @@ -72,9 +119,6 @@ else: sb_types = (unicode, bytes) -#============================================================================= -# bytes-specific helpers -#============================================================================= # bytes format #============================================================================= @@ -125,7 +169,7 @@ else: return method.im_func #============================================================================= -# output +# input/output #============================================================================= if PY3: import builtins diff --git a/passlib/utils/pbkdf2.py b/passlib/utils/pbkdf2.py index 9a7ee7c..aa35327 100644 --- a/passlib/utils/pbkdf2.py +++ b/passlib/utils/pbkdf2.py @@ -22,6 +22,7 @@ except ImportError: #pkg from passlib.utils import xor_bytes, to_bytes, native_str, b, bytes from passlib.utils.compat import irange, callable, int_types +from passlib.utils.compat.aliases import BytesIO #local __all__ = [ "hmac_sha1", @@ -30,12 +31,6 @@ __all__ = [ "pbkdf2", ] -# Py2k # -from cStringIO import StringIO as BytesIO -# Py3k # -#from io import BytesIO -# end Py3k # - #================================================================================= #quick hmac_sha1 implementation used various places #================================================================================= |
