summaryrefslogtreecommitdiff
path: root/passlib
diff options
context:
space:
mode:
authorEli Collins <elic@assurancetechnologies.com>2011-12-06 15:37:12 -0500
committerEli Collins <elic@assurancetechnologies.com>2011-12-06 15:37:12 -0500
commite2f085dd5606c4c1547803cfcbddd5796009f50f (patch)
treef9e25ef137a8a4a7f9308f69ed80cd4671e31a82 /passlib
parent44292a37537d62a399bc6c73b26948454d624cb0 (diff)
downloadpasslib-e2f085dd5606c4c1547803cfcbddd5796009f50f.tar.gz
added compat.aliased lazy-loading module, aliases for BytesIO/StringIO
Diffstat (limited to 'passlib')
-rw-r--r--passlib/context.py63
-rw-r--r--passlib/utils/__init__.py1
-rw-r--r--passlib/utils/_blowfish/__init__.py11
-rw-r--r--passlib/utils/compat.py52
-rw-r--r--passlib/utils/pbkdf2.py7
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
#=================================================================================