777 lines
24 KiB
Python
777 lines
24 KiB
Python
#Copyright ReportLab Europe Ltd. 2000-2004
|
|
#see license.txt for license details
|
|
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/lib/utils.py
|
|
__version__=''' $Id$ '''
|
|
|
|
import string, os, sys, imp
|
|
from types import *
|
|
from reportlab.lib.logger import warnOnce
|
|
SeqTypes = (ListType,TupleType)
|
|
if sys.hexversion<0x2030000:
|
|
True = 1
|
|
False = 0
|
|
|
|
def _findFiles(dirList,ext='.ttf'):
|
|
from os.path import isfile, isdir, join as path_join
|
|
from os import listdir
|
|
ext = ext.lower()
|
|
R = []
|
|
A = R.append
|
|
for D in dirList:
|
|
if not isdir(D): continue
|
|
for fn in listdir(D):
|
|
fn = path_join(D,fn)
|
|
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):
|
|
def __init__(self,*a,**kw):
|
|
map(self.update, a)
|
|
self.update(kw)
|
|
|
|
def update(self,D):
|
|
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)
|
|
|
|
def __getitem__(self,k):
|
|
try:
|
|
k = k.lower()
|
|
except:
|
|
pass
|
|
return _UserDict.__getitem__(self,k)
|
|
|
|
def __delitem__(self,k):
|
|
try:
|
|
k = k.lower()
|
|
except:
|
|
pass
|
|
return _UserDict.__delitem__(self,k)
|
|
|
|
def get(self,k,dv=None):
|
|
try:
|
|
return self[k]
|
|
except KeyError:
|
|
return dv
|
|
|
|
def has_key(self,k):
|
|
try:
|
|
self[k]
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
def pop(self,k,*a):
|
|
try:
|
|
k = k.lower()
|
|
except:
|
|
pass
|
|
return _UserDict.pop(*((self,k)+a))
|
|
|
|
def setdefault(self,k,*a):
|
|
try:
|
|
k = k.lower()
|
|
except:
|
|
pass
|
|
return _UserDict.setdefault(*((self,k)+a))
|
|
|
|
if os.name == 'mac':
|
|
#with the Mac, we need to tag the file in a special
|
|
#way so the system knows it is a PDF file.
|
|
#This supplied by Joe Strout
|
|
import macfs, macostools
|
|
_KNOWN_MAC_EXT = {
|
|
'BMP' : ('ogle','BMP '),
|
|
'EPS' : ('ogle','EPSF'),
|
|
'EPSF': ('ogle','EPSF'),
|
|
'GIF' : ('ogle','GIFf'),
|
|
'JPG' : ('ogle','JPEG'),
|
|
'JPEG': ('ogle','JPEG'),
|
|
'PCT' : ('ttxt','PICT'),
|
|
'PICT': ('ttxt','PICT'),
|
|
'PNG' : ('ogle','PNGf'),
|
|
'PPM' : ('ogle','.PPM'),
|
|
'TIF' : ('ogle','TIFF'),
|
|
'TIFF': ('ogle','TIFF'),
|
|
'PDF' : ('CARO','PDF '),
|
|
'HTML': ('MSIE','TEXT'),
|
|
}
|
|
def markfilename(filename,creatorcode=None,filetype=None,ext='PDF'):
|
|
try:
|
|
if creatorcode is None or filetype is None and ext is not None:
|
|
try:
|
|
creatorcode, filetype = _KNOWN_MAC_EXT[string.upper(ext)]
|
|
except:
|
|
return
|
|
macfs.FSSpec(filename).SetCreatorType(creatorcode,filetype)
|
|
macostools.touched(filename)
|
|
except:
|
|
pass
|
|
else:
|
|
def markfilename(filename,creatorcode=None,filetype=None):
|
|
pass
|
|
|
|
import reportlab
|
|
__RL_DIR=os.path.dirname(reportlab.__file__) #possibly relative
|
|
_RL_DIR=os.path.isabs(__RL_DIR) and __RL_DIR or os.path.abspath(__RL_DIR)
|
|
del reportlab
|
|
|
|
#Attempt to detect if this copy of reportlab is running in a
|
|
#file system (as opposed to mostly running in a zip or McMillan
|
|
#archive or Jar file). This is used by test cases, so that
|
|
#we can write test cases that don't get activated in a compiled
|
|
try:
|
|
__file__
|
|
except:
|
|
__file__ = sys.argv[0]
|
|
import glob, fnmatch
|
|
try:
|
|
_isFSD = not __loader__
|
|
_archive = __loader__.archive
|
|
_archivepfx = _archive + os.sep
|
|
_archivedir = os.path.dirname(__loader__.archive)
|
|
_archivedirpfx = _archivedir + os.sep
|
|
_archivepfxlen = len(_archivepfx)
|
|
_archivedirpfxlen = len(_archivedirpfx)
|
|
def __startswith_rl(fn,
|
|
_archivepfx=os.path.normcase(_archivepfx),
|
|
_archivedirpfx=os.path.normcase(_archivedirpfx),
|
|
_archive=os.path.normcase(_archive),
|
|
_archivedir=os.path.normcase(_archivedir),
|
|
os_path_normpath=os.path.normpath,
|
|
os_path_normcase=os.path.normcase,
|
|
os_getcwd=os.getcwd,
|
|
os_sep=os.sep,
|
|
os_sep_len = len(os.sep)):
|
|
'''if the name starts with a known prefix strip it off'''
|
|
fn = os_path_normpath(fn.replace('/',os_sep))
|
|
nfn = os_path_normcase(fn)
|
|
if nfn in (_archivedir,_archive): return 1,''
|
|
if nfn.startswith(_archivepfx): return 1,fn[_archivepfxlen:]
|
|
if nfn.startswith(_archivedirpfx): return 1,fn[_archivedirpfxlen:]
|
|
cwd = os_path_normcase(os_getcwd())
|
|
n = len(cwd)
|
|
if nfn.startswith(cwd):
|
|
if fn[n:].startswith(os_sep): return 1, fn[n+os_sep_len:]
|
|
if n==len(fn): return 1,''
|
|
return not os.path.isabs(fn),fn
|
|
|
|
def _startswith_rl(fn):
|
|
return __startswith_rl(fn)[1]
|
|
|
|
def rl_glob(pattern,glob=glob.glob,fnmatch=fnmatch.fnmatch, _RL_DIR=_RL_DIR,pjoin=os.path.join):
|
|
c, pfn = __startswith_rl(pattern)
|
|
r = glob(pfn)
|
|
if c or r==[]:
|
|
r += map(lambda x,D=_archivepfx,pjoin=pjoin: pjoin(_archivepfx,x),filter(lambda x,pfn=pfn,fnmatch=fnmatch: fnmatch(x,pfn),__loader__._files.keys()))
|
|
return r
|
|
except:
|
|
_isFSD = os.path.isfile(__file__) #slight risk of wrong path
|
|
__loader__ = None
|
|
def _startswith_rl(fn):
|
|
return fn
|
|
def rl_glob(pattern,glob=glob.glob):
|
|
return glob(pattern)
|
|
del glob, fnmatch
|
|
_isFSSD = _isFSD and os.path.isfile(os.path.splitext(__file__)[0] +'.py')
|
|
|
|
def isFileSystemDistro():
|
|
'''return truth if a file system distribution'''
|
|
return _isFSD
|
|
|
|
def isCompactDistro():
|
|
'''return truth if not a file system distribution'''
|
|
return not _isFSD
|
|
|
|
def isSourceDistro():
|
|
'''return truth if a source file system distribution'''
|
|
return _isFSSD
|
|
|
|
try:
|
|
#raise ImportError
|
|
### NOTE! FP_STR SHOULD PROBABLY ALWAYS DO A PYTHON STR() CONVERSION ON ARGS
|
|
### IN CASE THEY ARE "LAZY OBJECTS". ACCELLERATOR DOESN'T DO THIS (YET)
|
|
try:
|
|
from _rl_accel import fp_str # in case of builtin version
|
|
except ImportError:
|
|
from reportlab.lib._rl_accel import fp_str # specific
|
|
except ImportError:
|
|
from math import log
|
|
_log_10 = lambda x,log=log,_log_e_10=log(10.0): log(x)/_log_e_10
|
|
_fp_fmts = "%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f"
|
|
import re
|
|
_tz_re = re.compile('0+$')
|
|
del re
|
|
def fp_str(*a):
|
|
if len(a)==1 and type(a[0]) in SeqTypes: a = a[0]
|
|
s = []
|
|
A = s.append
|
|
for i in a:
|
|
sa =abs(i)
|
|
if sa<=1e-7: A('0')
|
|
else:
|
|
l = sa<=1 and 6 or min(max(0,(6-int(_log_10(sa)))),6)
|
|
n = _fp_fmts[l]%i
|
|
if l:
|
|
n = _tz_re.sub('',n)
|
|
try:
|
|
if n[-1]=='.': n = n[:-1]
|
|
except:
|
|
print i, n
|
|
raise
|
|
A((n[0]!='0' or len(n)==1) and n or n[1:])
|
|
return string.join(s)
|
|
|
|
#hack test for comma users
|
|
if ',' in fp_str(0.25):
|
|
_FP_STR = fp_str
|
|
def fp_str(*a):
|
|
return string.replace(apply(_FP_STR,a),',','.')
|
|
|
|
_rl_tempdir=None
|
|
def get_rl_tempdir(*subdirs):
|
|
global _rl_tempdir
|
|
if _rl_tempdir is None:
|
|
import tempfile
|
|
_rl_tempdir = os.path.join(tempfile.gettempdir(),'ReportLab_tmp%s' % (sys.platform=='unix' and `os.getuid()` or ''))
|
|
d = _rl_tempdir
|
|
if subdirs: d = os.path.join(*((d,)+subdirs))
|
|
try:
|
|
os.makedirs(d)
|
|
except:
|
|
pass
|
|
return d
|
|
|
|
def get_rl_tempfile(fn=None):
|
|
if not fn:
|
|
import tempfile
|
|
fn = tempfile.mktemp()
|
|
return os.path.join(get_rl_tempdir(),fn)
|
|
|
|
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 = map(normalize,sys.path)
|
|
if baseDir:
|
|
if type(baseDir) not in SeqTypes:
|
|
tp = [baseDir]
|
|
else:
|
|
tp = filter(None,list(baseDir))
|
|
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=',
|
|
pp(path)
|
|
|
|
#make import errors a bit more informative
|
|
opath = sys.path
|
|
try:
|
|
sys.path = path
|
|
exec 'import %s\nm = %s\n' % (modulename,modulename) in locals()
|
|
sys.path = opath
|
|
return m
|
|
except ImportError:
|
|
sys.path = opath
|
|
msg = "recursiveimport(%s,baseDir=%s) failed" % (modulename,baseDir)
|
|
if baseDir:
|
|
msg = msg + " under paths '%s'" % `path`
|
|
raise ImportError, msg
|
|
|
|
def recursiveGetAttr(obj, name):
|
|
"Can call down into e.g. object1.object2[4].attr"
|
|
return eval(name, obj.__dict__)
|
|
|
|
def recursiveSetAttr(obj, name, value):
|
|
"Can call down into e.g. object1.object2[4].attr = value"
|
|
#get the thing above last.
|
|
tokens = string.split(name, '.')
|
|
if len(tokens) == 1:
|
|
setattr(obj, name, value)
|
|
else:
|
|
most = string.join(tokens[:-1], '.')
|
|
last = tokens[-1]
|
|
parent = recursiveGetAttr(obj, most)
|
|
setattr(parent, last, value)
|
|
|
|
def import_zlib():
|
|
try:
|
|
import zlib
|
|
except ImportError:
|
|
zlib = None
|
|
from reportlab.rl_config import ZLIB_WARNINGS
|
|
if ZLIB_WARNINGS: warnOnce('zlib not available')
|
|
return zlib
|
|
|
|
|
|
# Image Capability Detection. Set a flag haveImages
|
|
# to tell us if either PIL or Java imaging libraries present.
|
|
# define PIL_Image as either None, or an alias for the PIL.Image
|
|
# module, as there are 2 ways to import it
|
|
|
|
if sys.platform[0:4] == 'java':
|
|
try:
|
|
import javax.imageio
|
|
import java.awt.image
|
|
haveImages = 1
|
|
except:
|
|
haveImages = 0
|
|
else:
|
|
try:
|
|
from PIL import Image
|
|
except ImportError:
|
|
try:
|
|
import Image
|
|
except ImportError:
|
|
Image = None
|
|
haveImages = Image is not None
|
|
if haveImages: del Image
|
|
|
|
|
|
__StringIO=None
|
|
def getStringIO(buf=None):
|
|
'''unified StringIO instance interface'''
|
|
global __StringIO
|
|
if not __StringIO:
|
|
try:
|
|
from cStringIO import StringIO
|
|
except ImportError:
|
|
from StringIO import StringIO
|
|
__StringIO = StringIO
|
|
return buf is not None and __StringIO(buf) or __StringIO()
|
|
|
|
class ArgvDictValue:
|
|
'''A type to allow clients of getArgvDict to specify a conversion function'''
|
|
def __init__(self,value,func):
|
|
self.value = value
|
|
self.func = func
|
|
|
|
def getArgvDict(**kw):
|
|
''' Builds a dictionary from its keyword arguments with overrides from sys.argv.
|
|
Attempts to be smart about conversions, but the value can be an instance
|
|
of ArgDictValue to allow specifying a conversion function.
|
|
'''
|
|
def handleValue(v,av,func):
|
|
if func:
|
|
v = func(av)
|
|
else:
|
|
t = type(v)
|
|
if t is StringType:
|
|
v = av
|
|
elif t is FloatType:
|
|
v = float(av)
|
|
elif t is IntType:
|
|
v = int(av)
|
|
elif t is ListType:
|
|
v = list(eval(av))
|
|
elif t is TupleType:
|
|
v = tuple(eval(av))
|
|
else:
|
|
raise TypeError, "Can't convert string '%s' to %s" % (av,str(t))
|
|
return v
|
|
|
|
A = sys.argv[1:]
|
|
R = {}
|
|
for k, v in kw.items():
|
|
if isinstance(v,ArgvDictValue):
|
|
v, func = v.value, v.func
|
|
else:
|
|
func = None
|
|
handled = 0
|
|
ke = k+'='
|
|
for a in A:
|
|
if string.find(a,ke)==0:
|
|
av = a[len(ke):]
|
|
A.remove(a)
|
|
R[k] = handleValue(v,av,func)
|
|
handled = 1
|
|
break
|
|
|
|
if not handled: R[k] = handleValue(v,v,func)
|
|
|
|
return R
|
|
|
|
def getHyphenater(hDict=None):
|
|
try:
|
|
from reportlab.lib.pyHnj import Hyphen
|
|
if hDict is None: hDict=os.path.join(os.path.dirname(__file__),'hyphen.mashed')
|
|
return Hyphen(hDict)
|
|
except ImportError, errMsg:
|
|
if str(errMsg)!='No module named pyHnj': raise
|
|
return None
|
|
|
|
def _className(self):
|
|
'''Return a shortened class name'''
|
|
try:
|
|
name = self.__class__.__name__
|
|
i=string.rfind(name,'.')
|
|
if i>=0: return name[i+1:]
|
|
return name
|
|
except AttributeError:
|
|
return str(self)
|
|
|
|
def open_for_read_by_name(name,mode='b'):
|
|
if 'r' not in mode: mode = 'r'+mode
|
|
try:
|
|
return open(name,mode)
|
|
except IOError:
|
|
if _isFSD or __loader__ is None: raise
|
|
#we have a __loader__, perhaps the filename starts with
|
|
#the dirname(reportlab.__file__) or is relative
|
|
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)
|
|
|
|
import urllib
|
|
def open_for_read(name,mode='b', urlopen=urllib.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())
|
|
except:
|
|
raise IOError('Cannot open resource "%s"' % name)
|
|
del urllib
|
|
|
|
def open_and_read(name,mode='b'):
|
|
return open_for_read(name,mode).read()
|
|
|
|
def open_and_readlines(name,mode='t'):
|
|
return open_and_read(name,mode).split('\n')
|
|
|
|
def rl_isfile(fn,os_path_isfile=os.path.isfile):
|
|
if hasattr(fn,'read'): return True
|
|
if os_path_isfile(fn): return True
|
|
if _isFSD or __loader__ is None: return False
|
|
fn = _startswith_rl(fn)
|
|
return fn in __loader__._files.keys()
|
|
|
|
def rl_isdir(pn,os_path_isdir=os.path.isdir,os_path_normpath=os.path.normpath):
|
|
if os_path_isdir(pn): return True
|
|
if _isFSD or __loader__ is None: return False
|
|
pn = _startswith_rl(os_path_normpath(pn))
|
|
if not pn.endswith(os.sep): pn += os.sep
|
|
return len(filter(lambda x,pn=pn: x.startswith(pn),__loader__._files.keys()))>0
|
|
|
|
def rl_get_module(name,dir):
|
|
if sys.modules.has_key(name):
|
|
om = sys.modules[name]
|
|
del sys.modules[name]
|
|
else:
|
|
om = None
|
|
try:
|
|
f = None
|
|
try:
|
|
f, p, desc= imp.find_module(name,[dir])
|
|
return imp.load_module(name,f,p,desc)
|
|
except:
|
|
if isCompactDistro():
|
|
#attempt a load from inside the zip archive
|
|
import zipimport
|
|
dir = _startswith_rl(dir)
|
|
dir = (dir=='.' or not dir) and _archive or os.path.join(_archive,dir.replace('/',os.sep))
|
|
zi = zipimport.zipimporter(dir)
|
|
return zi.load_module(name)
|
|
raise ImportError('%s[%s]' % (name,dir))
|
|
finally:
|
|
if om: sys.modules[name] = om
|
|
del om
|
|
if f: f.close()
|
|
|
|
class ImageReader:
|
|
"Wraps up either PIL or Java to get data from bitmaps"
|
|
def __init__(self, fileName):
|
|
if not haveImages:
|
|
warnOnce('Imaging Library not available, unable to import bitmaps')
|
|
return
|
|
#start wih lots of null private fields, to be populated by
|
|
#the relevant engine.
|
|
self.fileName = fileName
|
|
self._image = None
|
|
self._width = None
|
|
self._height = None
|
|
self._transparent = None
|
|
self._data = None
|
|
self.fp = open_for_read(fileName,'b')
|
|
|
|
#detect which library we are using and open the image
|
|
if sys.platform[0:4] == 'java':
|
|
from javax.imageio import ImageIO
|
|
self._image = ImageIO.read(self.fp)
|
|
else:
|
|
import PIL.Image
|
|
self._image = PIL.Image.open(self.fp)
|
|
|
|
def getSize(self):
|
|
if (self._width is None or self._height is None):
|
|
if sys.platform[0:4] == 'java':
|
|
self._width = self._image.getWidth()
|
|
self._height = self._image.getHeight()
|
|
else:
|
|
self._width, self._height = self._image.size
|
|
return (self._width, self._height)
|
|
|
|
def getRGBData(self):
|
|
"Return byte array of RGB data as string"
|
|
if self._data is None:
|
|
if sys.platform[0:4] == 'java':
|
|
import jarray
|
|
from java.awt.image import PixelGrabber
|
|
width, height = self.getSize()
|
|
buffer = jarray.zeros(width*height, 'i')
|
|
pg = PixelGrabber(self._image, 0,0,width,height,buffer,0,width)
|
|
pg.grabPixels()
|
|
# there must be a way to do this with a cast not a byte-level loop,
|
|
# I just haven't found it yet...
|
|
pixels = []
|
|
a = pixels.append
|
|
for i in range(len(buffer)):
|
|
rgb = buffer[i]
|
|
a(chr((rgb>>16)&0xff))
|
|
a(chr((rgb>>8)&0xff))
|
|
a(chr(rgb&0xff))
|
|
self._data = ''.join(pixels)
|
|
else:
|
|
rgb = self._image.convert('RGB')
|
|
self._data = rgb.tostring()
|
|
return self._data
|
|
|
|
def getImageData(self):
|
|
width, height = self.getSize()
|
|
return width, height, self.getRGBData()
|
|
|
|
def getTransparent(self):
|
|
if sys.platform[0:4] == 'java':
|
|
return None
|
|
else:
|
|
if self._image.info.has_key("transparency"):
|
|
transparency = self._image.info["transparency"] * 3
|
|
palette = self._image.palette
|
|
try:
|
|
palette = palette.palette
|
|
except:
|
|
palette = palette.data
|
|
return map(ord, palette[transparency:transparency+3])
|
|
else:
|
|
return None
|
|
|
|
def getImageData(imageFileName):
|
|
"Get width, height and RGB pixels from image file. Wraps Java/PIL"
|
|
return ImageReader.getImageData(imageFileName)
|
|
|
|
class DebugMemo:
|
|
'''Intended as a simple report back encapsulator
|
|
|
|
Typical usages
|
|
1) To record error data
|
|
dbg = DebugMemo(fn='dbgmemo.dbg',myVar=value)
|
|
dbg.add(anotherPayload='aaaa',andagain='bbb')
|
|
dbg.dump()
|
|
|
|
2) To show the recorded info
|
|
dbg = DebugMemo(fn='dbgmemo.dbg',mode='r')
|
|
dbg.load()
|
|
dbg.show()
|
|
|
|
3) To re-use recorded information
|
|
dbg = DebugMemo(fn='dbgmemo.dbg',mode='r')
|
|
dbg.load()
|
|
myTestFunc(dbg.payload('myVar'),dbg.payload('andagain'))
|
|
|
|
in addition to the payload variables the dump records many useful bits
|
|
of information which are also printed in the show() method.
|
|
'''
|
|
def __init__(self,fn='rl_dbgmemo.dbg',mode='w',getScript=1,modules=(),capture_traceback=1, stdout=None, **kw):
|
|
import time, socket
|
|
self.fn = fn
|
|
if mode!='w': return
|
|
if not stdout:
|
|
self.stdout = sys.stdout
|
|
else:
|
|
if hasattr(stdout,'write'):
|
|
self.stdout = stdout
|
|
else:
|
|
self.stdout = open(stdout,'w')
|
|
self.store = store = {}
|
|
if capture_traceback and sys.exc_info() != (None,None,None):
|
|
import traceback
|
|
s = getStringIO()
|
|
traceback.print_exc(None,s)
|
|
store['__traceback'] = s.getvalue()
|
|
cwd=os.getcwd()
|
|
lcwd = os.listdir(cwd)
|
|
exed = os.path.abspath(os.path.dirname(sys.argv[0]))
|
|
store.update({ 'gmt': time.asctime(time.gmtime(time.time())),
|
|
'platform': sys.platform,
|
|
'version': sys.version,
|
|
'hexversion': hex(sys.hexversion),
|
|
'executable': sys.executable,
|
|
'exec_prefix': sys.exec_prefix,
|
|
'prefix': sys.prefix,
|
|
'path': sys.path,
|
|
'argv': sys.argv,
|
|
'cwd': cwd,
|
|
'hostname': socket.gethostname(),
|
|
'lcwd': lcwd,
|
|
'byteorder': sys.byteorder,
|
|
'maxint': sys.maxint,
|
|
'maxint': getattr(sys,'maxunicode','????'),
|
|
'api_version': getattr(sys,'api_version','????'),
|
|
'version_info': getattr(sys,'version_info','????'),
|
|
'winver': getattr(sys,'winver','????'),
|
|
})
|
|
for M,A in (
|
|
(sys,('getwindowsversion','getfilesystemencoding')),
|
|
(os,('uname', 'ctermid', 'getgid', 'getuid', 'getegid',
|
|
'geteuid', 'getlogin', 'getgroups', 'getpgrp', 'getpid', 'getppid',
|
|
)),
|
|
):
|
|
for a in A:
|
|
if hasattr(M,a):
|
|
try:
|
|
store[a] = getattr(M,a)()
|
|
except:
|
|
pass
|
|
if exed!=cwd:
|
|
try:
|
|
store.update({'exed': exed, 'lexed': os.listdir(exed),})
|
|
except:
|
|
pass
|
|
if getScript:
|
|
fn = os.path.abspath(sys.argv[0])
|
|
if os.path.isfile(fn):
|
|
try:
|
|
store['__script'] = (fn,open(fn,'r').read())
|
|
except:
|
|
pass
|
|
module_versions = {}
|
|
for n,m in sys.modules.items():
|
|
if n=='reportlab' or n=='rlextra' or n[:10]=='reportlab.' or n[:8]=='rlextra.':
|
|
v = getattr(m,'__version__',None)
|
|
if v: module_versions[n] = v
|
|
store['__module_versions'] = module_versions
|
|
self.store['__payload'] = {}
|
|
self._add(kw)
|
|
|
|
def _add(self,D):
|
|
payload = self.store['__payload']
|
|
for k, v in D.items():
|
|
payload[k] = v
|
|
|
|
def add(self,**kw):
|
|
self._add(kw)
|
|
|
|
def dump(self):
|
|
import pickle
|
|
pickle.dump(self.store,open(self.fn,'wb'))
|
|
|
|
def load(self):
|
|
import pickle
|
|
self.store = pickle.load(open(self.fn,'rb'))
|
|
|
|
def _show_module_versions(self,k,v):
|
|
self._writeln(k[2:])
|
|
K = v.keys()
|
|
K.sort()
|
|
for k in K:
|
|
vk = v[k]
|
|
try:
|
|
m = recursiveImport(k,sys.path[:],1)
|
|
d = getattr(m,'__version__',None)==vk and 'SAME' or 'DIFFERENT'
|
|
except:
|
|
m = None
|
|
d = '??????unknown??????'
|
|
self._writeln(' %s = %s (%s)' % (k,vk,d))
|
|
|
|
def _banner(self,k,what):
|
|
self._writeln('###################%s %s##################' % (what,k[2:]))
|
|
|
|
def _start(self,k):
|
|
self._banner(k,'Start ')
|
|
|
|
def _finish(self,k):
|
|
self._banner(k,'Finish ')
|
|
|
|
def _show_lines(self,k,v):
|
|
self._start(k)
|
|
self._writeln(v)
|
|
self._finish(k)
|
|
|
|
def _show_file(self,k,v):
|
|
k = '%s %s' % (k,os.path.basename(v[0]))
|
|
self._show_lines(k,v[1])
|
|
|
|
def _show_payload(self,k,v):
|
|
if v:
|
|
import pprint
|
|
self._start(k)
|
|
pprint.pprint(v,self.stdout)
|
|
self._finish(k)
|
|
|
|
specials = {'__module_versions': _show_module_versions,
|
|
'__payload': _show_payload,
|
|
'__traceback': _show_lines,
|
|
'__script': _show_file,
|
|
}
|
|
def show(self):
|
|
K = self.store.keys()
|
|
K.sort()
|
|
for k in K:
|
|
if k not in self.specials.keys(): self._writeln('%-15s = %s' % (k,self.store[k]))
|
|
for k in K:
|
|
if k in self.specials.keys(): apply(self.specials[k],(self,k,self.store[k]))
|
|
|
|
def payload(self,name):
|
|
return self.store['__payload'][name]
|
|
|
|
def __setitem__(self,name,value):
|
|
self.store['__payload'][name] = value
|
|
|
|
def __getitem__(self,name):
|
|
return self.store['__payload'][name]
|
|
|
|
def _writeln(self,msg):
|
|
self.stdout.write(msg+'\n')
|
|
|
|
def _flatten(L,a):
|
|
for x in L:
|
|
if type(x) in SeqTypes: _flatten(x,a)
|
|
else: a(x)
|
|
|
|
def flatten(L):
|
|
'''recursively flatten the list or tuple L'''
|
|
R = []
|
|
_flatten(L,R.append)
|
|
return R
|
|
|
|
def find_locals(func,depth=0):
|
|
'''apply func to the locals at each stack frame till func returns a non false value'''
|
|
while 1:
|
|
_ = func(sys._getframe(depth).f_locals)
|
|
if _: return _
|
|
depth += 1
|