Package ldaptor :: Module compat'
[hide private]
[frames] | no frames]

Source Code for Module ldaptor.compat'

  1  """passlib.utils.compat - python 2/3 compatibility helpers""" 
  2  # Passlib is (c) `Assurance Technologies <http://www.assurancetechnologies.com>` 
  3  # and is released under the `BSD license <http://www.opensource.org/licenses/bsd-license.php>` 
  4   
  5  #============================================================================= 
  6  # figure out what we're running 
  7  #============================================================================= 
  8   
  9  #------------------------------------------------------------------------ 
 10  # python version 
 11  #------------------------------------------------------------------------ 
 12  import sys 
 13  PY2 = sys.version_info < (3,0) 
 14  PY3 = sys.version_info >= (3,0) 
 15  PY_MAX_25 = sys.version_info < (2,6) # py 2.5 or earlier 
 16  PY27 = sys.version_info[:2] == (2,7) # supports last 2.x release 
 17  PY_MIN_32 = sys.version_info >= (3,2) # py 3.2 or later 
 18   
 19  #------------------------------------------------------------------------ 
 20  # python implementation 
 21  #------------------------------------------------------------------------ 
 22  PYPY = hasattr(sys, "pypy_version_info") 
 23  JYTHON = sys.platform.startswith('java') 
 24   
 25  #------------------------------------------------------------------------ 
 26  # capabilities 
 27  #------------------------------------------------------------------------ 
 28   
 29  # __dir__() added in py2.6 
 30  SUPPORTS_DIR_METHOD = not PY_MAX_25 and not (PYPY and sys.pypy_version_info < (1,6)) 
 31   
 32  #============================================================================= 
 33  # common imports 
 34  #============================================================================= 
 35  import logging; log = logging.getLogger(__name__) 
 36  if PY3: 
 37      import builtins 
 38  else: 
 39      import __builtin__ as builtins 
40 41 -def add_doc(obj, doc):
42 """add docstring to an object""" 43 obj.__doc__ = doc
44 45 #============================================================================= 46 # the default exported vars 47 #============================================================================= 48 __all__ = [ 49 # python versions 50 'PY2', 'PY3', 'PY_MAX_25', 'PY27', 'PY_MIN_32', 51 52 # io 53 'BytesIO', 'StringIO', 'NativeStringIO', 'SafeConfigParser', 54 'print_', 55 56 # type detection 57 ## 'is_mapping', 58 'callable', 59 'int_types', 60 'num_types', 61 'base_string_types', 62 63 # unicode/bytes types & helpers 64 'u', 'b', 65 'unicode', 'bytes', 66 'uascii_to_str', 'bascii_to_str', 67 'str_to_uascii', 'str_to_bascii', 68 'join_unicode', 'join_bytes', 69 'join_byte_values', 'join_byte_elems', 70 'byte_elem_value', 71 'iter_byte_values', 72 73 # iteration helpers 74 'irange', #'lrange', 75 'imap', 'lmap', 76 'iteritems', 'itervalues', 77 'next', 78 79 # introspection 80 'exc_err', 'get_method_function', 'add_doc', 81 ] 82 83 # begin accumulating mapping of lazy-loaded attrs, 84 # 'merged' into module at bottom 85 _lazy_attrs = dict() 86 87 #============================================================================= 88 # unicode & bytes types 89 #============================================================================= 90 if PY3: 91 unicode = str 92 bytes = builtins.bytes
93 94 - def u(s):
95 assert isinstance(s, str) 96 return s
97
98 - def b(s):
99 assert isinstance(s, str) 100 return s.encode("latin-1")
101 102 base_string_types = (unicode, bytes) 103 104 else: 105 unicode = builtins.unicode 106 bytes = str if PY_MAX_25 else builtins.bytes
107 108 - def u(s):
109 assert isinstance(s, str) 110 return s.decode("unicode_escape")
111
112 - def b(s):
113 assert isinstance(s, str) 114 return s
115 116 base_string_types = basestring 117 118 #============================================================================= 119 # unicode & bytes helpers 120 #============================================================================= 121 # function to join list of unicode strings 122 join_unicode = u('').join 123 124 # function to join list of byte strings 125 join_bytes = b('').join 126 127 if PY3:
128 - def uascii_to_str(s):
129 assert isinstance(s, unicode) 130 return s
131
132 - def bascii_to_str(s):
133 assert isinstance(s, bytes) 134 return s.decode("ascii")
135
136 - def str_to_uascii(s):
137 assert isinstance(s, str) 138 return s
139
140 - def str_to_bascii(s):
141 assert isinstance(s, str) 142 return s.encode("ascii")
143 144 join_byte_values = join_byte_elems = bytes
145 146 - def byte_elem_value(elem):
147 assert isinstance(elem, int) 148 return elem
149
150 - def iter_byte_values(s):
151 assert isinstance(s, bytes) 152 return s
153
154 - def iter_byte_chars(s):
155 assert isinstance(s, bytes) 156 # FIXME: there has to be a better way to do this 157 return (bytes([c]) for c in s)
158 159 else:
160 - def uascii_to_str(s):
161 assert isinstance(s, unicode) 162 return s.encode("ascii")
163
164 - def bascii_to_str(s):
165 assert isinstance(s, bytes) 166 return s
167
168 - def str_to_uascii(s):
169 assert isinstance(s, str) 170 return s.decode("ascii")
171
172 - def str_to_bascii(s):
173 assert isinstance(s, str) 174 return s
175
176 - def join_byte_values(values):
177 return join_bytes(chr(v) for v in values)
178 179 join_byte_elems = join_bytes 180 181 byte_elem_value = ord
182 183 - def iter_byte_values(s):
184 assert isinstance(s, bytes) 185 return (ord(c) for c in s)
186
187 - def iter_byte_chars(s):
188 assert isinstance(s, bytes) 189 return s
190 191 add_doc(uascii_to_str, "helper to convert ascii unicode -> native str") 192 add_doc(bascii_to_str, "helper to convert ascii bytes -> native str") 193 add_doc(str_to_uascii, "helper to convert ascii native str -> unicode") 194 add_doc(str_to_bascii, "helper to convert ascii native str -> bytes") 195 196 # join_byte_values -- function to convert list of ordinal integers to byte string. 197 198 # join_byte_elems -- function to convert list of byte elements to byte string; 199 # i.e. what's returned by ``b('a')[0]``... 200 # this is b('a') under PY2, but 97 under PY3. 201 202 # byte_elem_value -- function to convert byte element to integer -- a noop under PY3 203 204 add_doc(iter_byte_values, "iterate over byte string as sequence of ints 0-255") 205 add_doc(iter_byte_chars, "iterate over byte string as sequence of 1-byte strings") 206 207 #============================================================================= 208 # numeric 209 #============================================================================= 210 if PY3: 211 int_types = (int,) 212 num_types = (int, float) 213 else: 214 int_types = (int, long) 215 num_types = (int, long, float) 216 217 #============================================================================= 218 # iteration helpers 219 # 220 # irange - range iterable / view (xrange under py2, range under py3) 221 # lrange - range list (range under py2, list(range()) under py3) 222 # 223 # imap - map to iterator 224 # lmap - map to list 225 #============================================================================= 226 if PY3: 227 irange = range
228 ##def lrange(*a,**k): 229 ## return list(range(*a,**k)) 230 231 - def lmap(*a, **k):
232 return list(map(*a,**k))
233 imap = map
234 235 - def iteritems(d):
236 return d.items()
237 - def itervalues(d):
238 return d.values()
239 240 next_method_attr = "__next__" 241 242 else: 243 irange = xrange 244 ##lrange = range 245 246 lmap = map 247 from itertools import imap
248 249 - def iteritems(d):
250 return d.iteritems()
251 - def itervalues(d):
252 return d.itervalues()
253 254 next_method_attr = "next" 255 256 if PY_MAX_25: 257 _undef = object()
258 - def next(itr, default=_undef):
259 "compat wrapper for next()" 260 if default is _undef: 261 return itr.next() 262 try: 263 return itr.next() 264 except StopIteration: 265 return default
266 else: 267 next = builtins.next 268 269 #============================================================================= 270 # typing 271 #============================================================================= 272 ##def is_mapping(obj): 273 ## # non-exhaustive check, enough to distinguish from lists, etc 274 ## return hasattr(obj, "items") 275 276 if (3,0) <= sys.version_info < (3,2): 277 # callable isn't dead, it's just resting 278 from collections import Callable
279 - def callable(obj):
280 return isinstance(obj, Callable)
281 else: 282 callable = builtins.callable
283 284 #============================================================================= 285 # introspection 286 #============================================================================= 287 -def exc_err():
288 "return current error object (to avoid try/except syntax change)" 289 return sys.exc_info()[1]
290 291 if PY3: 292 method_function_attr = "__func__" 293 else: 294 method_function_attr = "im_func"
295 296 -def get_method_function(func):
297 "given (potential) method, return underlying function" 298 return getattr(func, method_function_attr, func)
299 300 #============================================================================= 301 # input/output 302 #============================================================================= 303 if PY3: 304 _lazy_attrs = dict( 305 BytesIO="io.BytesIO", 306 UnicodeIO="io.StringIO", 307 NativeStringIO="io.StringIO", 308 SafeConfigParser="configparser.SafeConfigParser", 309 ) 310 if sys.version_info >= (3,2): 311 # py32 renamed this, removing old ConfigParser 312 _lazy_attrs["SafeConfigParser"] = "configparser.ConfigParser" 313 314 print_ = getattr(builtins, "print") 315 316 else: 317 _lazy_attrs = dict( 318 BytesIO="cStringIO.StringIO", 319 UnicodeIO="StringIO.StringIO", 320 NativeStringIO="cStringIO.StringIO", 321 SafeConfigParser="ConfigParser.SafeConfigParser", 322 ) 365 366 #============================================================================= 367 # lazy overlay module 368 #============================================================================= 369 from types import ModuleType
370 371 -def _import_object(source):
372 "helper to import object from module; accept format `path.to.object`" 373 modname, modattr = source.rsplit(".",1) 374 mod = __import__(modname, fromlist=[modattr], level=0) 375 return getattr(mod, modattr)
376
377 -class _LazyOverlayModule(ModuleType):
378 """proxy module which overlays original module, 379 and lazily imports specified attributes. 380 381 this is mainly used to prevent importing of resources 382 that are only needed by certain password hashes, 383 yet allow them to be imported from a single location. 384 385 used by :mod:`passlib.utils`, :mod:`passlib.utils.crypto`, 386 and :mod:`passlib.utils.compat`. 387 """ 388 389 @classmethod
390 - def replace_module(cls, name, attrmap):
391 orig = sys.modules[name] 392 self = cls(name, attrmap, orig) 393 sys.modules[name] = self 394 return self
395
396 - def __init__(self, name, attrmap, proxy=None):
397 ModuleType.__init__(self, name) 398 self.__attrmap = attrmap 399 self.__proxy = proxy 400 self.__log = logging.getLogger(name)
401
402 - def __getattr__(self, attr):
403 proxy = self.__proxy 404 if proxy and hasattr(proxy, attr): 405 return getattr(proxy, attr) 406 attrmap = self.__attrmap 407 if attr in attrmap: 408 source = attrmap[attr] 409 if callable(source): 410 value = source() 411 else: 412 value = _import_object(source) 413 setattr(self, attr, value) 414 self.__log.debug("loaded lazy attr %r: %r", attr, value) 415 return value 416 raise AttributeError("'module' object has no attribute '%s'" % (attr,))
417
418 - def __repr__(self):
419 proxy = self.__proxy 420 if proxy: 421 return repr(proxy) 422 else: 423 return ModuleType.__repr__(self)
424
425 - def __dir__(self):
426 attrs = set(dir(self.__class__)) 427 attrs.update(self.__dict__) 428 attrs.update(self.__attrmap) 429 proxy = self.__proxy 430 if proxy is not None: 431 attrs.update(dir(proxy)) 432 return list(attrs)
433 434 # replace this module with overlay that will lazily import attributes. 435 _LazyOverlayModule.replace_module(__name__, _lazy_attrs) 436 437 #============================================================================= 438 # eof 439 #============================================================================= 440