src/reportlab/lib/utils.py
branchpy33
changeset 3723 99aa837b6703
parent 3721 0c93dd8ff567
child 3725 ca840494f9dd
equal deleted inserted replaced
3722:29c11b905751 3723:99aa837b6703
     3 # $URI:$
     3 # $URI:$
     4 __version__=''' $Id$ '''
     4 __version__=''' $Id$ '''
     5 __doc__='''Gazillions of miscellaneous internal utility functions'''
     5 __doc__='''Gazillions of miscellaneous internal utility functions'''
     6 
     6 
     7 import os, sys, imp, time
     7 import os, sys, imp, time
     8 try:
     8 import base64
     9     from hashlib import md5
     9 import pickle
    10 except:
    10 from io import BytesIO
    11     from md5 import md5
    11 import hashlib
    12 from reportlab.lib.logger import warnOnce
    12 from reportlab.lib.logger import warnOnce
    13 from .rltempfile import get_rl_tempfile, get_rl_tempdir, _rl_getuid
    13 from .rltempfile import get_rl_tempfile, get_rl_tempdir, _rl_getuid
    14 
       
    15 def isSeqType(v,_st=(tuple,list)):
       
    16     return isinstance(v,_st)
       
    17 
       
    18 if sys.hexversion<0x2030000:
       
    19     True = 1
       
    20     False = 0
       
    21 
    14 
    22 if sys.hexversion >= 0x02000000:
    15 if sys.hexversion >= 0x02000000:
    23     def _digester(s):
    16     def _digester(s):
    24         return md5(s).hexdigest()
    17         return md5(s).hexdigest()
    25 else:
    18 else:
    26     # hexdigest not available in 1.5
    19     # hexdigest not available in 1.5
    27     def _digester(s):
    20     def _digester(s):
    28         return join(["%02x" % ord(x) for x in md5(s).digest()], '')
    21         return join(["%02x" % ord(x) for x in md5(s).digest()], '')
       
    22 
       
    23 isPython3 = sys.version_info[0]==3
       
    24 
       
    25 def isFunctionType(v):
       
    26     return type(v) == type(isFunctionType)
       
    27 
       
    28 class c:
       
    29     def m(self): pass
       
    30 
       
    31 def isMethodType(v,mt=type(c.m)):
       
    32     return type(v) == mt
       
    33 del c
       
    34 
       
    35 def isModuleType(v):
       
    36     return type(v) == type(sys)
       
    37 
       
    38 def isSeqType(v,_st=(tuple,list)):
       
    39     return isinstance(v,_st)
       
    40 
       
    41 if isPython3:
       
    42     def UniChr(v):
       
    43         return chr(v)
       
    44 
       
    45     def isStrType(v):
       
    46         return isinstance(v, str)
       
    47 
       
    48     def isBytesType(v):
       
    49         return isinstance(v, bytes)
       
    50 
       
    51     def isUnicodeType(v):
       
    52         return isinstance(v, str)
       
    53 
       
    54     def isClassType(v):
       
    55         return isinstance(v, type)
       
    56 else:
       
    57     def UniChr(v):
       
    58         return unichr(v)
       
    59 
       
    60     def isStrType(v):
       
    61         return isinstance(v, basestring)
       
    62 
       
    63     def isBytesType(v):
       
    64         return isinstance(v, str)
       
    65 
       
    66     def isUnicodeType(v):
       
    67         return isinstance(v, unicode)
       
    68 
       
    69     def isClassType(v):
       
    70         import types
       
    71         return isinstance(v, types.ClassType)
    29 
    72 
    30 def _findFiles(dirList,ext='.ttf'):
    73 def _findFiles(dirList,ext='.ttf'):
    31     from os.path import isfile, isdir, join as path_join
    74     from os.path import isfile, isdir, join as path_join
    32     from os import listdir
    75     from os import listdir
    33     ext = ext.lower()
    76     ext = ext.lower()
    38         for fn in listdir(D):
    81         for fn in listdir(D):
    39             fn = path_join(D,fn)
    82             fn = path_join(D,fn)
    40             if isfile(fn) and (not ext or fn.lower().endswith(ext)): A(fn)
    83             if isfile(fn) and (not ext or fn.lower().endswith(ext)): A(fn)
    41     return R
    84     return R
    42 
    85 
    43 try:
    86 class CIDict(dict):
    44     _UserDict = dict
       
    45 except:
       
    46     from UserDict import UserDict as _UserDict
       
    47 
       
    48 class CIDict(_UserDict):
       
    49     def __init__(self,*args,**kwds):
    87     def __init__(self,*args,**kwds):
    50         for a in args: self.update(a)
    88         for a in args: self.update(a)
    51         self.update(kwds)
    89         self.update(kwds)
    52 
    90 
    53     def update(self,D):
    91     def update(self,D):
    54         for k,v in list(D.items()): self[k] = v
    92         for k,v in D.items(): self[k] = v
    55 
    93 
    56     def __setitem__(self,k,v):
    94     def __setitem__(self,k,v):
    57         try:
    95         try:
    58             k = k.lower()
    96             k = k.lower()
    59         except:
    97         except:
    60             pass
    98             pass
    61         _UserDict.__setitem__(self,k,v)
    99         dict.__setitem__(self,k,v)
    62 
   100 
    63     def __getitem__(self,k):
   101     def __getitem__(self,k):
    64         try:
   102         try:
    65             k = k.lower()
   103             k = k.lower()
    66         except:
   104         except:
    67             pass
   105             pass
    68         return _UserDict.__getitem__(self,k)
   106         return dict.__getitem__(self,k)
    69 
   107 
    70     def __delitem__(self,k):
   108     def __delitem__(self,k):
    71         try:
   109         try:
    72             k = k.lower()
   110             k = k.lower()
    73         except:
   111         except:
    74             pass
   112             pass
    75         return _UserDict.__delitem__(self,k)
   113         return dict.__delitem__(self,k)
    76 
   114 
    77     def get(self,k,dv=None):
   115     def get(self,k,dv=None):
    78         try:
   116         try:
    79             return self[k]
   117             return self[k]
    80         except KeyError:
   118         except KeyError:
    90     def pop(self,k,*a):
   128     def pop(self,k,*a):
    91         try:
   129         try:
    92             k = k.lower()
   130             k = k.lower()
    93         except:
   131         except:
    94             pass
   132             pass
    95         return _UserDict.pop(*((self,k)+a))
   133         return dict.pop(*((self,k)+a))
    96 
   134 
    97     def setdefault(self,k,*a):
   135     def setdefault(self,k,*a):
    98         try:
   136         try:
    99             k = k.lower()
   137             k = k.lower()
   100         except:
   138         except:
   101             pass
   139             pass
   102         return _UserDict.setdefault(*((self,k)+a))
   140         return dict.setdefault(*((self,k)+a))
   103 
   141 
   104 if os.name == 'mac':
   142 if os.name == 'mac':
   105     #with the Mac, we need to tag the file in a special
   143     #with the Mac, we need to tag the file in a special
   106     #way so the system knows it is a PDF file.
   144     #way so the system knows it is a PDF file.
   107     #This supplied by Joe Strout
   145     #This supplied by Joe Strout
   253 if ',' in fp_str(0.25):
   291 if ',' in fp_str(0.25):
   254     _FP_STR = fp_str
   292     _FP_STR = fp_str
   255     def fp_str(*a):
   293     def fp_str(*a):
   256         return _FP_STR(*a).replace(',','.')
   294         return _FP_STR(*a).replace(',','.')
   257 
   295 
   258 def recursiveImport(modulename, baseDir=None, noCWD=0, debug=0):
       
   259     """Dynamically imports possible packagized module, or raises ImportError"""
       
   260     normalize = lambda x: os.path.normcase(os.path.abspath(os.path.normpath(x)))
       
   261     path = list(map(normalize,sys.path))
       
   262     if baseDir:
       
   263         if not isSeqType(baseDir):
       
   264             tp = [baseDir]
       
   265         else:
       
   266             tp = [_f for _f in list(baseDir) if _f]
       
   267         for p in tp:
       
   268             p = normalize(p)
       
   269             if p not in path: path.insert(0,p)
       
   270 
       
   271     if noCWD:
       
   272         for p in ('','.',normalize('.')):
       
   273             while p in path:
       
   274                 if debug: print('removed "%s" from path' % p)
       
   275                 path.remove(p)
       
   276     elif '.' not in path:
       
   277             path.insert(0,'.')
       
   278 
       
   279     if debug:
       
   280         import pprint
       
   281         pp = pprint.pprint
       
   282         print('path=', end=' ')
       
   283         pp(path)
       
   284 
       
   285     #make import errors a bit more informative
       
   286     opath = sys.path
       
   287     try:
       
   288         sys.path = path
       
   289         exec('import %s\nm = %s\n' % (modulename,modulename), locals())
       
   290         sys.path = opath
       
   291         return m
       
   292     except ImportError:
       
   293         sys.path = opath
       
   294         msg = "Could not import '%s'" % modulename
       
   295         if baseDir:
       
   296             msg = msg + " under %s" % baseDir
       
   297         raise ImportError(msg)
       
   298 
       
   299     except Exception, e:
       
   300         msg = "Exception raised while importing '%s': %s" % (modulename, e.message)
       
   301         raise ImportError(msg)
       
   302         
       
   303 
       
   304 def recursiveGetAttr(obj, name):
   296 def recursiveGetAttr(obj, name):
   305     "Can call down into e.g. object1.object2[4].attr"
   297     "Can call down into e.g. object1.object2[4].attr"
   306     return eval(name, obj.__dict__)
   298     return eval(name, obj.__dict__)
   307 
   299 
   308 def recursiveSetAttr(obj, name, value):
   300 def recursiveSetAttr(obj, name, value):
   345             import Image
   337             import Image
   346         except ImportError:
   338         except ImportError:
   347             Image = None
   339             Image = None
   348     haveImages = Image is not None
   340     haveImages = Image is not None
   349 
   341 
   350 try:
   342 def getBytesIO(buf=None):
   351     from io import StringIO as __StringIO
       
   352 except ImportError:
       
   353     from io import StringIO as __StringIO
       
   354 def getStringIO(buf=None):
       
   355     '''unified StringIO instance interface'''
   343     '''unified StringIO instance interface'''
   356     return buf is not None and __StringIO(buf) or __StringIO()
   344     if buf:
   357 _StringIOKlass=__StringIO().__class__
   345         return BytesIO(buf)
       
   346     return BytesIO()
   358 
   347 
   359 class ArgvDictValue:
   348 class ArgvDictValue:
   360     '''A type to allow clients of getArgvDict to specify a conversion function'''
   349     '''A type to allow clients of getArgvDict to specify a conversion function'''
   361     def __init__(self,value,func):
   350     def __init__(self,value,func):
   362         self.value = value
   351         self.value = value
   369     '''
   358     '''
   370     def handleValue(v,av,func):
   359     def handleValue(v,av,func):
   371         if func:
   360         if func:
   372             v = func(av)
   361             v = func(av)
   373         else:
   362         else:
   374             if isinstance(v,str):
   363             if isStrType(v):
   375                 if isinstance(v,str): v = v.encode('utf8')
       
   376                 v = av
   364                 v = av
   377             elif isinstance(v,float):
   365             elif isinstance(v,float):
   378                 v = float(av)
   366                 v = float(av)
   379             elif isinstance(v,int):
   367             elif isinstance(v,int):
   380                 v = int(av)
   368                 v = int(av)
   386                 raise TypeError("Can't convert string %r to %s" % (av,type(v)))
   374                 raise TypeError("Can't convert string %r to %s" % (av,type(v)))
   387         return v
   375         return v
   388 
   376 
   389     A = sys.argv[1:]
   377     A = sys.argv[1:]
   390     R = {}
   378     R = {}
   391     for k, v in list(kw.items()):
   379     for k, v in kw.items():
   392         if isinstance(v,ArgvDictValue):
   380         if isinstance(v,ArgvDictValue):
   393             v, func = v.value, v.func
   381             v, func = v.value, v.func
   394         else:
   382         else:
   395             func = None
   383             func = None
   396         handled = 0
   384         handled = 0
   435         #we have a __loader__, perhaps the filename starts with
   423         #we have a __loader__, perhaps the filename starts with
   436         #the dirname(reportlab.__file__) or is relative
   424         #the dirname(reportlab.__file__) or is relative
   437         name = _startswith_rl(name)
   425         name = _startswith_rl(name)
   438         s = __loader__.get_data(name)
   426         s = __loader__.get_data(name)
   439         if 'b' not in mode and os.linesep!='\n': s = s.replace(os.linesep,'\n')
   427         if 'b' not in mode and os.linesep!='\n': s = s.replace(os.linesep,'\n')
   440         return getStringIO(s)
   428         return getBytesIO(s)
   441 
   429 
   442 import urllib.request, urllib.error, urllib.parse
   430 try:
   443 def open_for_read(name,mode='b', urlopen=urllib.request.urlopen):
   431     import urllib2
       
   432     urlopen=urllib2.urlopen
       
   433 except ImportError:
       
   434     import urllib.request
       
   435     urlopen=urllib.request.urlopen
       
   436 
       
   437 def open_for_read(name,mode='b', urlopen=urlopen):
   444     '''attempt to open a file or URL for reading'''
   438     '''attempt to open a file or URL for reading'''
   445     if hasattr(name,'read'): return name
   439     if hasattr(name,'read'): return name
   446     try:
   440     try:
   447         return open_for_read_by_name(name,mode)
   441         return open_for_read_by_name(name,mode)
   448     except:
   442     except:
   449         try:
   443         try:
   450             return getStringIO(urlopen(name).read())
   444             return getBytesIO(urlopen(name).read())
   451         except:
   445         except:
   452             raise IOError('Cannot open resource "%s"' % name)
   446             raise IOError('Cannot open resource "%s"' % name)
   453 del urllib2
   447 del urlopen
   454 
   448 
   455 def open_and_read(name,mode='b'):
   449 def open_and_read(name,mode='b'):
   456     return open_for_read(name,mode).read()
   450     return open_for_read(name,mode).read()
   457 
   451 
   458 def open_and_readlines(name,mode='t'):
   452 def open_and_readlines(name,mode='t'):
   474 
   468 
   475 def rl_listdir(pn,os_path_isdir=os.path.isdir,os_path_normpath=os.path.normpath,os_listdir=os.listdir):
   469 def rl_listdir(pn,os_path_isdir=os.path.isdir,os_path_normpath=os.path.normpath,os_listdir=os.listdir):
   476     if os_path_isdir(pn) or _isFSD or __loader__ is None: return os_listdir(pn)
   470     if os_path_isdir(pn) or _isFSD or __loader__ is None: return os_listdir(pn)
   477     pn = _startswith_rl(os_path_normpath(pn))
   471     pn = _startswith_rl(os_path_normpath(pn))
   478     if not pn.endswith(os.sep): pn += os.sep
   472     if not pn.endswith(os.sep): pn += os.sep
   479     return [x[len(pn):] for x in list(__loader__._files.keys()) if x.startswith(pn)]
   473     return [x[len(pn):] for x in __loader__._files.keys() if x.startswith(pn)]
   480 
   474 
   481 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):
   475 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):
   482     if os_path_isfile(pn) or _isFSD or __loader__ is None: return os_path_getmtime(pn)
   476     if os_path_isfile(pn) or _isFSD or __loader__ is None: return os_path_getmtime(pn)
   483     p = _startswith_rl(os_path_normpath(pn))
   477     p = _startswith_rl(os_path_normpath(pn))
   484     try:
   478     try:
   545                 self.fileName = 'PILIMAGE_%d' % id(self)
   539                 self.fileName = 'PILIMAGE_%d' % id(self)
   546         else:
   540         else:
   547             try:
   541             try:
   548                 from reportlab.rl_config import imageReaderFlags
   542                 from reportlab.rl_config import imageReaderFlags
   549                 self.fp = open_for_read(fileName,'b')
   543                 self.fp = open_for_read(fileName,'b')
   550                 if isinstance(self.fp,_StringIOKlass):  imageReaderFlags=0 #avoid messing with already internal files
   544                 if isinstance(self.fp,BytesIO): imageReaderFlags=0 #avoid messing with already internal files
   551                 if imageReaderFlags>0:  #interning
   545                 if imageReaderFlags>0:  #interning
   552                     data = self.fp.read()
   546                     data = self.fp.read()
   553                     if imageReaderFlags&2:  #autoclose
   547                     if imageReaderFlags&2:  #autoclose
   554                         try:
   548                         try:
   555                             self.fp.close()
   549                             self.fp.close()
   558                     if imageReaderFlags&4:  #cache the data
   552                     if imageReaderFlags&4:  #cache the data
   559                         if not self._cache:
   553                         if not self._cache:
   560                             from rl_config import register_reset
   554                             from rl_config import register_reset
   561                             register_reset(self._cache.clear)
   555                             register_reset(self._cache.clear)
   562                         data=self._cache.setdefault(md5(data).digest(),data)
   556                         data=self._cache.setdefault(md5(data).digest(),data)
   563                     self.fp=getStringIO(data)
   557                     self.fp=getBytesIO(data)
   564                 elif imageReaderFlags==-1 and isinstance(fileName,str):
   558                 elif imageReaderFlags==-1 and isinstance(fileName,str):
   565                     #try Ralf Schmitt's re-opening technique of avoiding too many open files
   559                     #try Ralf Schmitt's re-opening technique of avoiding too many open files
   566                     self.fp.close()
   560                     self.fp.close()
   567                     del self.fp #will become a property in the next statement
   561                     del self.fp #will become a property in the next statement
   568                     self.__class__=LazyImageReader
   562                     self.__class__=LazyImageReader
   585                 annotateException('\nfileName=%r identity=%s'%(fileName,self.identity()))
   579                 annotateException('\nfileName=%r identity=%s'%(fileName,self.identity()))
   586 
   580 
   587     def identity(self):
   581     def identity(self):
   588         '''try to return information that will identify the instance'''
   582         '''try to return information that will identify the instance'''
   589         fn = self.fileName
   583         fn = self.fileName
   590         if not isinstance(fn,str):
   584         if not isStrType(fn):
   591             fn = getattr(getattr(self,'fp',None),'name',None)
   585             fn = getattr(getattr(self,'fp',None),'name',None)
   592         ident = self._ident
   586         ident = self._ident
   593         return '[%s@%s%s%s]' % (self.__class__.__name__,hex(id(self)),ident and (' ident=%r' % ident) or '',fn and (' filename=%r' % fn) or '')
   587         return '[%s@%s%s%s]' % (self.__class__.__name__,hex(id(self)),ident and (' ident=%r' % ident) or '',fn and (' filename=%r' % fn) or '')
   594 
   588 
   595     def _read_image(self,fp):
   589     def _read_image(self,fp):
   668                 palette = self._image.palette
   662                 palette = self._image.palette
   669                 try:
   663                 try:
   670                     palette = palette.palette
   664                     palette = palette.palette
   671                 except:
   665                 except:
   672                     palette = palette.data
   666                     palette = palette.data
   673                 return list(map(ord, palette[transparency:transparency+3]))
   667                 if isPython3:
       
   668                     return palette[transparency:transparency+3]
       
   669                 else:
       
   670                     return [ord(c) for c in palette[transparency:transparency+3]]
   674             else:
   671             else:
   675                 return None
   672                 return None
   676 
   673 
   677 class LazyImageReader(ImageReader): 
   674 class LazyImageReader(ImageReader): 
   678     def fp(self): 
   675     def fp(self): 
   728                 self.stdout = open(stdout,'w')
   725                 self.stdout = open(stdout,'w')
   729         if mode!='w': return
   726         if mode!='w': return
   730         self.store = store = {}
   727         self.store = store = {}
   731         if capture_traceback and sys.exc_info() != (None,None,None):
   728         if capture_traceback and sys.exc_info() != (None,None,None):
   732             import traceback
   729             import traceback
   733             s = getStringIO()
   730             s = getBytesIO()
   734             traceback.print_exc(None,s)
   731             traceback.print_exc(None,s)
   735             store['__traceback'] = s.getvalue()
   732             store['__traceback'] = s.getvalue()
   736         cwd=os.getcwd()
   733         cwd=os.getcwd()
   737         lcwd = os.listdir(cwd)
   734         lcwd = os.listdir(cwd)
   738         pcwd = os.path.dirname(cwd)
   735         pcwd = os.path.dirname(cwd)
   761                         'cwd': cwd,
   758                         'cwd': cwd,
   762                         'hostname': socket.gethostname(),
   759                         'hostname': socket.gethostname(),
   763                         'lcwd': lcwd,
   760                         'lcwd': lcwd,
   764                         'lpcwd': lpcwd,
   761                         'lpcwd': lpcwd,
   765                         'byteorder': sys.byteorder,
   762                         'byteorder': sys.byteorder,
   766                         'maxint': sys.maxsize,
       
   767                         'maxint': getattr(sys,'maxunicode','????'),
   763                         'maxint': getattr(sys,'maxunicode','????'),
   768                         'api_version': getattr(sys,'api_version','????'),
   764                         'api_version': getattr(sys,'api_version','????'),
   769                         'version_info': getattr(sys,'version_info','????'),
   765                         'version_info': getattr(sys,'version_info','????'),
   770                         'winver': getattr(sys,'winver','????'),
   766                         'winver': getattr(sys,'winver','????'),
   771                         'environment': '\n\t\t\t'.join(['']+['%s=%r' % (k,env[k]) for k in K]),
   767                         'environment': '\n\t\t\t'.join(['']+['%s=%r' % (k,env[k]) for k in K]),
   796                 try:
   792                 try:
   797                     store['__script'] = (fn,open(fn,'r').read())
   793                     store['__script'] = (fn,open(fn,'r').read())
   798                 except:
   794                 except:
   799                     pass
   795                     pass
   800         module_versions = {}
   796         module_versions = {}
   801         for n,m in list(sys.modules.items()):
   797         for n,m in sys.modules.items():
   802             if n=='reportlab' or n=='rlextra' or n[:10]=='reportlab.' or n[:8]=='rlextra.':
   798             if n=='reportlab' or n=='rlextra' or n[:10]=='reportlab.' or n[:8]=='rlextra.':
   803                 v = [getattr(m,x,None) for x in ('__version__','__path__','__file__')]
   799                 v = [getattr(m,x,None) for x in ('__version__','__path__','__file__')]
   804                 if [_f for _f in v if _f]:
   800                 if [_f for _f in v if _f]:
   805                     v = [v[0]] + [_f for _f in v[1:] if _f]
   801                     v = [v[0]] + [_f for _f in v[1:] if _f]
   806                     module_versions[n] = tuple(v)
   802                     module_versions[n] = tuple(v)
   808         self.store['__payload'] = {}
   804         self.store['__payload'] = {}
   809         self._add(kw)
   805         self._add(kw)
   810 
   806 
   811     def _add(self,D):
   807     def _add(self,D):
   812         payload = self.store['__payload']
   808         payload = self.store['__payload']
   813         for k, v in list(D.items()):
   809         for k, v in D.items():
   814             payload[k] = v
   810             payload[k] = v
   815 
   811 
   816     def add(self,**kw):
   812     def add(self,**kw):
   817         self._add(kw)
   813         self._add(kw)
   818 
   814 
   819     def _dump(self,f):
   815     def _dump(self,f):
   820         import pickle
       
   821         try:
   816         try:
   822             pos=f.tell()
   817             pos=f.tell()
   823             pickle.dump(self.store,f)
   818             pickle.dump(self.store,f)
   824         except:
   819         except:
   825             S=self.store.copy()
   820             S=self.store.copy()
   826             ff=getStringIO()
   821             ff=getBytesIO()
   827             for k,v in S.items():
   822             for k,v in S.items():
   828                 try:
   823                 try:
   829                     pickle.dump({k:v},ff)
   824                     pickle.dump({k:v},ff)
   830                 except:
   825                 except:
   831                     S[k] = '<unpicklable object %r>' % v
   826                     S[k] = '<unpicklable object %r>' % v
   838             self._dump(f)
   833             self._dump(f)
   839         finally:
   834         finally:
   840             f.close()
   835             f.close()
   841 
   836 
   842     def dumps(self):
   837     def dumps(self):
   843         f = getStringIO()
   838         f = getBytesIO()
   844         self._dump(f)
   839         self._dump(f)
   845         return f.getvalue()
   840         return f.getvalue()
   846 
   841 
   847     def _load(self,f):
   842     def _load(self,f):
   848         import pickle
       
   849         self.store = pickle.load(f)
   843         self.store = pickle.load(f)
   850 
   844 
   851     def load(self):
   845     def load(self):
   852         f = open(self.fn,'rb')
   846         f = open(self.fn,'rb')
   853         try:
   847         try:
   854             self._load(f)
   848             self._load(f)
   855         finally:
   849         finally:
   856             f.close()
   850             f.close()
   857 
   851 
   858     def loads(self,s):
   852     def loads(self,s):
   859         self._load(getStringIO(s))
   853         self._load(getBytesIO(s))
   860 
   854 
   861     def _show_module_versions(self,k,v):
   855     def _show_module_versions(self,k,v):
   862         self._writeln(k[2:])
   856         self._writeln(k[2:])
   863         K = list(v.keys())
   857         K = list(v.keys())
   864         K.sort()
   858         K.sort()
   865         for k in K:
   859         for k in K:
   866             vk = vk0 = v[k]
   860             vk = vk0 = v[k]
   867             if isinstance(vk,tuple): vk0 = vk[0]
   861             if isinstance(vk,tuple): vk0 = vk[0]
   868             try:
   862             try:
   869                 m = recursiveImport(k,sys.path[:],1)
   863                 __import__(k)
       
   864                 m = sys.modules[k]
   870                 d = getattr(m,'__version__',None)==vk0 and 'SAME' or 'DIFFERENT'
   865                 d = getattr(m,'__version__',None)==vk0 and 'SAME' or 'DIFFERENT'
   871             except:
   866             except:
   872                 m = None
   867                 m = None
   873                 d = '??????unknown??????'
   868                 d = '??????unknown??????'
   874             self._writeln('  %s = %s (%s)' % (k,vk,d))
   869             self._writeln('  %s = %s (%s)' % (k,vk,d))
   900 
   895 
   901     def _show_extensions(self):
   896     def _show_extensions(self):
   902         for mn in ('_rl_accel','_renderPM','sgmlop','pyRXP','pyRXPU','_imaging','Image'):
   897         for mn in ('_rl_accel','_renderPM','sgmlop','pyRXP','pyRXPU','_imaging','Image'):
   903             try:
   898             try:
   904                 A = [mn].append
   899                 A = [mn].append
   905                 m = recursiveImport(mn,sys.path[:],1)
   900                 __import__(mn)
       
   901                 m = sys.modules[mn]
   906                 A(m.__file__)
   902                 A(m.__file__)
   907                 for vn in ('__version__','VERSION','_version','version'):
   903                 for vn in ('__version__','VERSION','_version','version'):
   908                     if hasattr(m,vn):
   904                     if hasattr(m,vn):
   909                         A('%s=%r' % (vn,getattr(m,vn)))
   905                         A('%s=%r' % (vn,getattr(m,vn)))
   910             except:
   906             except:
  1120     for i,a in enumerate(A):
  1116     for i,a in enumerate(A):
  1121         if isinstance(a,str):
  1117         if isinstance(a,str):
  1122             e = i
  1118             e = i
  1123             break
  1119             break
  1124     if e>=0:
  1120     if e>=0:
  1125         if isinstance(a,str):
  1121         if not isPython3:
  1126             if not isinstance(msg,str):
  1122             if isinstance(a,unicode):
  1127                 msg=msg.decode(enc)
  1123                 if not isinstance(msg,unicode):
  1128         else:
  1124                     msg=msg.decode(enc)
  1129             if isinstance(msg,str):
       
  1130                 msg=msg.encode(enc)
       
  1131             else:
  1125             else:
  1132                 msg = str(msg)
  1126                 if isinstance(msg,unicode):
       
  1127                     msg=msg.encode(enc)
       
  1128                 else:
       
  1129                     msg = str(msg)
  1133         if isinstance(v,IOError) and getattr(v,'strerror',None):
  1130         if isinstance(v,IOError) and getattr(v,'strerror',None):
  1134             v.strerror = msg+'\n'+str(v.strerror)
  1131             v.strerror = msg+'\n'+str(v.strerror)
  1135         else:
  1132         else:
  1136             A[e] += msg
  1133             A[e] += msg
  1137     else:
  1134     else:
  1164     data = data.replace("&amp;amp;", "&amp;")
  1161     data = data.replace("&amp;amp;", "&amp;")
  1165     data = data.replace("&amp;gt;", "&gt;")
  1162     data = data.replace("&amp;gt;", "&gt;")
  1166     data = data.replace("&amp;lt;", "&lt;")
  1163     data = data.replace("&amp;lt;", "&lt;")
  1167     return data
  1164     return data
  1168 
  1165 
       
  1166 def encode_label(args):
       
  1167     s = base64.encodestring(pickle.dumps(args)).strip()
       
  1168     if not isStrType(s):
       
  1169         s = s.decode('utf-8')
       
  1170     return s
       
  1171 
       
  1172 def decode_label(label):
       
  1173     if isUnicodeType(label):
       
  1174         label = label.encode('utf-8')
       
  1175     v = pickle.loads(base64.decodestring(label))
       
  1176     return v
       
  1177     
  1169 class IdentStr(str):
  1178 class IdentStr(str):
  1170     '''useful for identifying things that get split'''
  1179     '''useful for identifying things that get split'''
  1171     def __new__(cls,value):
  1180     def __new__(cls,value):
  1172         if isinstance(value,IdentStr):
  1181         if isinstance(value,IdentStr):
  1173             inc = value.__inc
  1182             inc = value.__inc