src/reportlab/lib/utils.py
branchpy33
changeset 3723 99aa837b6703
parent 3721 0c93dd8ff567
child 3725 ca840494f9dd
--- a/src/reportlab/lib/utils.py	Sun Feb 17 12:13:56 2013 +0000
+++ b/src/reportlab/lib/utils.py	Tue Apr 30 14:28:14 2013 +0100
@@ -5,20 +5,13 @@
 __doc__='''Gazillions of miscellaneous internal utility functions'''
 
 import os, sys, imp, time
-try:
-    from hashlib import md5
-except:
-    from md5 import md5
+import base64
+import pickle
+from io import BytesIO
+import hashlib
 from reportlab.lib.logger import warnOnce
 from .rltempfile import get_rl_tempfile, get_rl_tempdir, _rl_getuid
 
-def isSeqType(v,_st=(tuple,list)):
-    return isinstance(v,_st)
-
-if sys.hexversion<0x2030000:
-    True = 1
-    False = 0
-
 if sys.hexversion >= 0x02000000:
     def _digester(s):
         return md5(s).hexdigest()
@@ -27,6 +20,56 @@
     def _digester(s):
         return join(["%02x" % ord(x) for x in md5(s).digest()], '')
 
+isPython3 = sys.version_info[0]==3
+
+def isFunctionType(v):
+    return type(v) == type(isFunctionType)
+
+class c:
+    def m(self): pass
+
+def isMethodType(v,mt=type(c.m)):
+    return type(v) == mt
+del c
+
+def isModuleType(v):
+    return type(v) == type(sys)
+
+def isSeqType(v,_st=(tuple,list)):
+    return isinstance(v,_st)
+
+if isPython3:
+    def UniChr(v):
+        return chr(v)
+
+    def isStrType(v):
+        return isinstance(v, str)
+
+    def isBytesType(v):
+        return isinstance(v, bytes)
+
+    def isUnicodeType(v):
+        return isinstance(v, str)
+
+    def isClassType(v):
+        return isinstance(v, type)
+else:
+    def UniChr(v):
+        return unichr(v)
+
+    def isStrType(v):
+        return isinstance(v, basestring)
+
+    def isBytesType(v):
+        return isinstance(v, str)
+
+    def isUnicodeType(v):
+        return isinstance(v, unicode)
+
+    def isClassType(v):
+        import types
+        return isinstance(v, types.ClassType)
+
 def _findFiles(dirList,ext='.ttf'):
     from os.path import isfile, isdir, join as path_join
     from os import listdir
@@ -40,39 +83,34 @@
             if isfile(fn) and (not ext or fn.lower().endswith(ext)): A(fn)
     return R
 
-try:
-    _UserDict = dict
-except:
-    from UserDict import UserDict as _UserDict
-
-class CIDict(_UserDict):
+class CIDict(dict):
     def __init__(self,*args,**kwds):
         for a in args: self.update(a)
         self.update(kwds)
 
     def update(self,D):
-        for k,v in list(D.items()): self[k] = v
+        for k,v in D.items(): self[k] = v
 
     def __setitem__(self,k,v):
         try:
             k = k.lower()
         except:
             pass
-        _UserDict.__setitem__(self,k,v)
+        dict.__setitem__(self,k,v)
 
     def __getitem__(self,k):
         try:
             k = k.lower()
         except:
             pass
-        return _UserDict.__getitem__(self,k)
+        return dict.__getitem__(self,k)
 
     def __delitem__(self,k):
         try:
             k = k.lower()
         except:
             pass
-        return _UserDict.__delitem__(self,k)
+        return dict.__delitem__(self,k)
 
     def get(self,k,dv=None):
         try:
@@ -92,14 +130,14 @@
             k = k.lower()
         except:
             pass
-        return _UserDict.pop(*((self,k)+a))
+        return dict.pop(*((self,k)+a))
 
     def setdefault(self,k,*a):
         try:
             k = k.lower()
         except:
             pass
-        return _UserDict.setdefault(*((self,k)+a))
+        return dict.setdefault(*((self,k)+a))
 
 if os.name == 'mac':
     #with the Mac, we need to tag the file in a special
@@ -255,52 +293,6 @@
     def fp_str(*a):
         return _FP_STR(*a).replace(',','.')
 
-def recursiveImport(modulename, baseDir=None, noCWD=0, debug=0):
-    """Dynamically imports possible packagized module, or raises ImportError"""
-    normalize = lambda x: os.path.normcase(os.path.abspath(os.path.normpath(x)))
-    path = list(map(normalize,sys.path))
-    if baseDir:
-        if not isSeqType(baseDir):
-            tp = [baseDir]
-        else:
-            tp = [_f for _f in list(baseDir) if _f]
-        for p in tp:
-            p = normalize(p)
-            if p not in path: path.insert(0,p)
-
-    if noCWD:
-        for p in ('','.',normalize('.')):
-            while p in path:
-                if debug: print('removed "%s" from path' % p)
-                path.remove(p)
-    elif '.' not in path:
-            path.insert(0,'.')
-
-    if debug:
-        import pprint
-        pp = pprint.pprint
-        print('path=', end=' ')
-        pp(path)
-
-    #make import errors a bit more informative
-    opath = sys.path
-    try:
-        sys.path = path
-        exec('import %s\nm = %s\n' % (modulename,modulename), locals())
-        sys.path = opath
-        return m
-    except ImportError:
-        sys.path = opath
-        msg = "Could not import '%s'" % modulename
-        if baseDir:
-            msg = msg + " under %s" % baseDir
-        raise ImportError(msg)
-
-    except Exception, e:
-        msg = "Exception raised while importing '%s': %s" % (modulename, e.message)
-        raise ImportError(msg)
-        
-
 def recursiveGetAttr(obj, name):
     "Can call down into e.g. object1.object2[4].attr"
     return eval(name, obj.__dict__)
@@ -347,14 +339,11 @@
             Image = None
     haveImages = Image is not None
 
-try:
-    from io import StringIO as __StringIO
-except ImportError:
-    from io import StringIO as __StringIO
-def getStringIO(buf=None):
+def getBytesIO(buf=None):
     '''unified StringIO instance interface'''
-    return buf is not None and __StringIO(buf) or __StringIO()
-_StringIOKlass=__StringIO().__class__
+    if buf:
+        return BytesIO(buf)
+    return BytesIO()
 
 class ArgvDictValue:
     '''A type to allow clients of getArgvDict to specify a conversion function'''
@@ -371,8 +360,7 @@
         if func:
             v = func(av)
         else:
-            if isinstance(v,str):
-                if isinstance(v,str): v = v.encode('utf8')
+            if isStrType(v):
                 v = av
             elif isinstance(v,float):
                 v = float(av)
@@ -388,7 +376,7 @@
 
     A = sys.argv[1:]
     R = {}
-    for k, v in list(kw.items()):
+    for k, v in kw.items():
         if isinstance(v,ArgvDictValue):
             v, func = v.value, v.func
         else:
@@ -437,20 +425,26 @@
         name = _startswith_rl(name)
         s = __loader__.get_data(name)
         if 'b' not in mode and os.linesep!='\n': s = s.replace(os.linesep,'\n')
-        return getStringIO(s)
+        return getBytesIO(s)
 
-import urllib.request, urllib.error, urllib.parse
-def open_for_read(name,mode='b', urlopen=urllib.request.urlopen):
+try:
+    import urllib2
+    urlopen=urllib2.urlopen
+except ImportError:
+    import urllib.request
+    urlopen=urllib.request.urlopen
+
+def open_for_read(name,mode='b', urlopen=urlopen):
     '''attempt to open a file or URL for reading'''
     if hasattr(name,'read'): return name
     try:
         return open_for_read_by_name(name,mode)
     except:
         try:
-            return getStringIO(urlopen(name).read())
+            return getBytesIO(urlopen(name).read())
         except:
             raise IOError('Cannot open resource "%s"' % name)
-del urllib2
+del urlopen
 
 def open_and_read(name,mode='b'):
     return open_for_read(name,mode).read()
@@ -476,7 +470,7 @@
     if os_path_isdir(pn) or _isFSD or __loader__ is None: return os_listdir(pn)
     pn = _startswith_rl(os_path_normpath(pn))
     if not pn.endswith(os.sep): pn += os.sep
-    return [x[len(pn):] for x in list(__loader__._files.keys()) if x.startswith(pn)]
+    return [x[len(pn):] for x in __loader__._files.keys() if x.startswith(pn)]
 
 def rl_getmtime(pn,os_path_isfile=os.path.isfile,os_path_normpath=os.path.normpath,os_path_getmtime=os.path.getmtime,time_mktime=time.mktime):
     if os_path_isfile(pn) or _isFSD or __loader__ is None: return os_path_getmtime(pn)
@@ -547,7 +541,7 @@
             try:
                 from reportlab.rl_config import imageReaderFlags
                 self.fp = open_for_read(fileName,'b')
-                if isinstance(self.fp,_StringIOKlass):  imageReaderFlags=0 #avoid messing with already internal files
+                if isinstance(self.fp,BytesIO): imageReaderFlags=0 #avoid messing with already internal files
                 if imageReaderFlags>0:  #interning
                     data = self.fp.read()
                     if imageReaderFlags&2:  #autoclose
@@ -560,7 +554,7 @@
                             from rl_config import register_reset
                             register_reset(self._cache.clear)
                         data=self._cache.setdefault(md5(data).digest(),data)
-                    self.fp=getStringIO(data)
+                    self.fp=getBytesIO(data)
                 elif imageReaderFlags==-1 and isinstance(fileName,str):
                     #try Ralf Schmitt's re-opening technique of avoiding too many open files
                     self.fp.close()
@@ -587,7 +581,7 @@
     def identity(self):
         '''try to return information that will identify the instance'''
         fn = self.fileName
-        if not isinstance(fn,str):
+        if not isStrType(fn):
             fn = getattr(getattr(self,'fp',None),'name',None)
         ident = self._ident
         return '[%s@%s%s%s]' % (self.__class__.__name__,hex(id(self)),ident and (' ident=%r' % ident) or '',fn and (' filename=%r' % fn) or '')
@@ -670,7 +664,10 @@
                     palette = palette.palette
                 except:
                     palette = palette.data
-                return list(map(ord, palette[transparency:transparency+3]))
+                if isPython3:
+                    return palette[transparency:transparency+3]
+                else:
+                    return [ord(c) for c in palette[transparency:transparency+3]]
             else:
                 return None
 
@@ -730,7 +727,7 @@
         self.store = store = {}
         if capture_traceback and sys.exc_info() != (None,None,None):
             import traceback
-            s = getStringIO()
+            s = getBytesIO()
             traceback.print_exc(None,s)
             store['__traceback'] = s.getvalue()
         cwd=os.getcwd()
@@ -763,7 +760,6 @@
                         'lcwd': lcwd,
                         'lpcwd': lpcwd,
                         'byteorder': sys.byteorder,
-                        'maxint': sys.maxsize,
                         'maxint': getattr(sys,'maxunicode','????'),
                         'api_version': getattr(sys,'api_version','????'),
                         'version_info': getattr(sys,'version_info','????'),
@@ -798,7 +794,7 @@
                 except:
                     pass
         module_versions = {}
-        for n,m in list(sys.modules.items()):
+        for n,m in sys.modules.items():
             if n=='reportlab' or n=='rlextra' or n[:10]=='reportlab.' or n[:8]=='rlextra.':
                 v = [getattr(m,x,None) for x in ('__version__','__path__','__file__')]
                 if [_f for _f in v if _f]:
@@ -810,20 +806,19 @@
 
     def _add(self,D):
         payload = self.store['__payload']
-        for k, v in list(D.items()):
+        for k, v in D.items():
             payload[k] = v
 
     def add(self,**kw):
         self._add(kw)
 
     def _dump(self,f):
-        import pickle
         try:
             pos=f.tell()
             pickle.dump(self.store,f)
         except:
             S=self.store.copy()
-            ff=getStringIO()
+            ff=getBytesIO()
             for k,v in S.items():
                 try:
                     pickle.dump({k:v},ff)
@@ -840,12 +835,11 @@
             f.close()
 
     def dumps(self):
-        f = getStringIO()
+        f = getBytesIO()
         self._dump(f)
         return f.getvalue()
 
     def _load(self,f):
-        import pickle
         self.store = pickle.load(f)
 
     def load(self):
@@ -856,7 +850,7 @@
             f.close()
 
     def loads(self,s):
-        self._load(getStringIO(s))
+        self._load(getBytesIO(s))
 
     def _show_module_versions(self,k,v):
         self._writeln(k[2:])
@@ -866,7 +860,8 @@
             vk = vk0 = v[k]
             if isinstance(vk,tuple): vk0 = vk[0]
             try:
-                m = recursiveImport(k,sys.path[:],1)
+                __import__(k)
+                m = sys.modules[k]
                 d = getattr(m,'__version__',None)==vk0 and 'SAME' or 'DIFFERENT'
             except:
                 m = None
@@ -902,7 +897,8 @@
         for mn in ('_rl_accel','_renderPM','sgmlop','pyRXP','pyRXPU','_imaging','Image'):
             try:
                 A = [mn].append
-                m = recursiveImport(mn,sys.path[:],1)
+                __import__(mn)
+                m = sys.modules[mn]
                 A(m.__file__)
                 for vn in ('__version__','VERSION','_version','version'):
                     if hasattr(m,vn):
@@ -1122,14 +1118,15 @@
             e = i
             break
     if e>=0:
-        if isinstance(a,str):
-            if not isinstance(msg,str):
-                msg=msg.decode(enc)
-        else:
-            if isinstance(msg,str):
-                msg=msg.encode(enc)
+        if not isPython3:
+            if isinstance(a,unicode):
+                if not isinstance(msg,unicode):
+                    msg=msg.decode(enc)
             else:
-                msg = str(msg)
+                if isinstance(msg,unicode):
+                    msg=msg.encode(enc)
+                else:
+                    msg = str(msg)
         if isinstance(v,IOError) and getattr(v,'strerror',None):
             v.strerror = msg+'\n'+str(v.strerror)
         else:
@@ -1166,6 +1163,18 @@
     data = data.replace("&amp;lt;", "&lt;")
     return data
 
+def encode_label(args):
+    s = base64.encodestring(pickle.dumps(args)).strip()
+    if not isStrType(s):
+        s = s.decode('utf-8')
+    return s
+
+def decode_label(label):
+    if isUnicodeType(label):
+        label = label.encode('utf-8')
+    v = pickle.loads(base64.decodestring(label))
+    return v
+    
 class IdentStr(str):
     '''useful for identifying things that get split'''
     def __new__(cls,value):