Package topo :: Package misc :: Module asizeof
[hide private]
[frames] | no frames]

Source Code for Module topo.misc.asizeof

   1  #!/usr/bin/env python 
   2   
   3  # Copyright, license and disclaimer are at the end of this file. 
   4   
   5  # This is the latest, enhanced version of the asizeof.py recipes at 
   6  # <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/546530> 
   7  # <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/544288> 
   8   
   9  '''This module exposes 10 functions and 2 classes to obtain lengths 
  10     and sizes of Python objects (for Python 2.2 or later [1]). 
  11   
  12     The main changes in this version are new function  calcsize(), 
  13     use  gc.get_objects() to get all objects and improvements in 
  14     this documentation. 
  15   
  16  Public Functions [2] 
  17   
  18     Function  asizeof calculates the combined (approximate) size 
  19     in bytes of one or several Python objects. 
  20   
  21     Function  asizesof returns a tuple containing the (approximate) 
  22     size in bytes for each given Python object separately. 
  23   
  24     Function  asized returns for each object an instance of class 
  25     Asized containing all the size information of the object and a 
  26     tuple with the referents. 
  27   
  28     Functions  basicsize and  itemsize return the basic respectively 
  29     item size of the given object. 
  30   
  31     Function  flatsize returns the flat size of a Python object in 
  32     bytes defined as the basic size plus the item size times the 
  33     length of the given object. 
  34   
  35     Function  leng returns the length of an object, like standard 
  36     len but extended for several types, e.g. the  leng of a multi- 
  37     precision int (or long) is the number of digits [3].  The length 
  38     of most mutable sequence objects includes an estimate of the 
  39     over-allocation and therefore, the  leng value may differ from 
  40     the standard  len result. 
  41   
  42     Function  refs returns (a generator for) the referents of the 
  43     given object, i.e. the objects referenced by the given object. 
  44   
  45     Function  calcsize is equivalent to standard  struct.calcsize 
  46     but handles format characters 'z' for signed C type  Py_ssize_t 
  47     and 'Z' for unsigned C type  size_t. 
  48   
  49     Certain classes are known to be sub-classes of or to behave as 
  50     dict objects.  Function  adict can be used to install other 
  51     class objects to be treated like dict. 
  52   
  53  Public Classes [2] 
  54   
  55     An instance of class  Asized is returned for each object sized 
  56     with the  asized function or method. 
  57   
  58     Class  Asizer can be used to accumulate the results of several 
  59     asizeof or  asizesof calls.  After creating an  Asizer instance, 
  60     use methods  asizeof and  asizesof to size additional objects. 
  61   
  62     Call methods  exclude_refs and/or  exclude_types to exclude 
  63     references to or instances or types of certain objects. 
  64   
  65     Use one of the  print\_... methods to report the statistics. 
  66   
  67  Duplicate Objects 
  68   
  69     Any duplicate, given objects are sized only once and the size 
  70     is included in the combined total only once.  But functions 
  71     asizesof and  asized do return a size value respectively an 
  72     Asized instance for each given object, the same for duplicates. 
  73   
  74  Definitions [4] 
  75   
  76     The size of an object is defined as the sum of the flat size 
  77     of the object plus the sizes of any referents.  Referents are 
  78     visited recursively up to a given limit.  However, the size 
  79     of objects referenced multiple times is included only once. 
  80   
  81     The flat size of an object is defined as the basic size of the 
  82     object plus the item size times the number of allocated items. 
  83     The flat size does include the size for the items (references 
  84     to the referents), but not the referents themselves. 
  85   
  86     The flat size returned by function  flatsize equals the result 
  87     of the  asizeof function with options code=True, ignored=False, 
  88     limit=0 and option  align set to the same value. 
  89   
  90     The accurate flat size for an object is obtained from function 
  91     sys.getsizeof() where available.  Otherwise, the length and 
  92     size of sequence objects as dicts, lists, sets, etc. is based 
  93     on an estimate for the number of allocated items.  As a result, 
  94     the reported length and size may substantially differ from the 
  95     actual length and size. 
  96   
  97     The basic and item sizes are obtained from the __basicsize__ 
  98     respectively __itemsize__ attribute of the (type of the) object. 
  99     Where necessary (e.g. sequence objects), a zero __itemsize__ 
 100     is replaced by the size of a corresponding C type. 
 101   
 102     The basic size (of GC managed objects) objects includes the 
 103     overhead for Python's garbage collector (GC) as well as the 
 104     space needed for refcounts (only in certain Python builds). 
 105   
 106     Optionally, sizes can be aligned to any power of 2 multiple. 
 107   
 108  Size of (byte)code 
 109   
 110     The (byte)code size of objects as classes, functions, methods, 
 111     modules, etc. can be included by setting option  code. 
 112   
 113     Iterators are handled similar to sequences: iterated object(s) 
 114     are sized like referents if the recursion limit permits.  Also, 
 115     function  gc.get_referents() must return the referent object 
 116     of iterators. 
 117   
 118     Generators are sized as (byte)code only, but generated objects 
 119     are never sized. 
 120   
 121  Old- and New-style Classes 
 122   
 123     All old- and new-style class, instance and type objects, are 
 124     handled uniformly such that (a) instance and class objects can 
 125     be distinguished and (b) instances of different old-style 
 126     classes can be dealt with separately. 
 127   
 128     Class and type objects are represented as <class ....* def> 
 129     respectively as <type ... def> where an '*' indicates an old- 
 130     style class and the  def suffix marks the definition object. 
 131     Instances of old-style classes are shown as new-style ones but 
 132     with an '*' at the end of the name, like <class module.name*>. 
 133   
 134  Ignored Objects 
 135   
 136     To avoid excessive sizes, several object types are ignored [4] 
 137     by default, e.g. built-in functions, built-in types and classes 
 138     [5], function globals and module referents.  However, any 
 139     instances thereof are sized and module objects will be sized 
 140     when passed as given objects.  Ignored object types are included 
 141     if option  ignored is set accordingly. 
 142   
 143     In addition, many __...__ attributes of callable objects are 
 144     ignored, except crucial ones, e.g. class attributes __dict__, 
 145     __doc__, __name__ and __slots__.  For more details, see the 
 146     type-specific _..._refs() and _len_...() functions below. 
 147   
 148     Option  all can be used to size all Python objects and/or get 
 149     the referents from  gc.get_referents() and override the type- 
 150     specific __..._refs() functions. 
 151   
 152  Notes 
 153   
 154     [1] Tested with Python 2.2.3, 2.3.7, 2.4.5, 2.5.1, 2.5.2, 2.6.2, 
 155         3.0.1 or 3.1a2 on CentOS 4.6, SuSE 9.3, MacOS X 10.4.11 Tiger 
 156         (Intel) and 10.3.9 Panther (PPC), Solaris 10 (Opteron) and 
 157         Windows XP all 32-bit Python and on RHEL 3u7 and Solaris 10 
 158         (Opteron) both 64-bit Python. 
 159   
 160     [2] The functions and classes in this module are not thread-safe. 
 161   
 162     [3] See Python source file .../Include/longinterp.h for the 
 163         C typedef of digit used in multi-precision int (or long) 
 164         objects.  The size of digit in bytes can be obtained in 
 165         Python from the int (or long) __itemsize__ attribute. 
 166         Function  leng (rather _len_int) below deterimines the 
 167         number of digits from the int (or long) value. 
 168   
 169     [4] These definitions and other assumptions are rather arbitrary 
 170         and may need corrections or adjustments. 
 171   
 172     [5] Types and classes are considered built-in if the module of 
 173         the type or class is listed in  _builtin_modules below. 
 174   
 175  '''  #PYCHOK expected 
 176   
 177  from __future__ import generators  #PYCHOK for yield in Python 2.2 
 178   
 179  from inspect    import isbuiltin, isclass, iscode, isframe, \ 
 180                         isfunction, ismethod, ismodule, stack 
 181  from math       import log 
 182  from os         import linesep 
 183  from struct     import calcsize as _calcsize 
 184  import sys 
 185  import types    as     Types 
 186  import weakref  as     Weakref 
 187   
 188  __version__ = '5.12 (Apr 27, 2009)' 
 189  __all__     = ['adict', 'asized', 'asizeof', 'asizesof', 
 190                 'Asized', 'Asizer',  # classes 
 191                 'basicsize', 'flatsize', 'itemsize', 'leng', 'refs', 
 192                 'calcsize']  # handles 'z' and 'Z' 
 193   
 194   # any classes or types in modules listed in _builtin_modules are 
 195   # considered built-in and ignored by default, as built-in functions 
 196  if __name__ == '__main__': 
 197      _builtin_modules = (int.__module__, 'types', Exception.__module__)  # , 'weakref' 
 198  else:  # treat this very module as built-in 
 199      _builtin_modules = (int.__module__, 'types', Exception.__module__, __name__)  # , 'weakref' 
 200   
 201   # sizes of some primitive C types 
 202   # XXX len(pack(T, 0)) == Struct(T).size == _calcsize(T) 
 203   # but type/class Struct only available since Python 2.5 
 204  _sizeof_Cbyte  = _calcsize('c')  # sizeof(unsigned char) 
 205  _sizeof_Clong  = _calcsize('l')  # sizeof(long) 
 206  _sizeof_Cvoidp = _calcsize('P')  # sizeof(void*) 
 207   
 208   # sizeof(long) != sizeof(ssize_t) on LLP64 
 209  if _sizeof_Clong < _sizeof_Cvoidp: 
 210      _Zz = 'PP' 
 211  else: 
 212      _Zz = 'Ll' 
 213   
214 -def calcsize(fmt):
215 '''struct.calcsize() handling 'z' for signed Py_ssize_t and 'Z' for unsigned size_t. 216 ''' 217 return _calcsize(fmt.replace('Z', _Zz[0]).replace('z', _Zz[1]))
218 219 # defaults for some basic sizes with 'z' for C Py_ssize_t 220 _sizeof_CPyCodeObject = calcsize('Pz10P5i0P') # sizeof(PyCodeObject) 221 _sizeof_CPyFrameObject = calcsize('Pzz13P63i0P') # sizeof(PyFrameObject) 222 _sizeof_CPyModuleObject = calcsize('PzP0P') # sizeof(PyModuleObject) 223 224 # defaults for some item sizes with 'z' for C Py_ssize_t 225 _sizeof_CPyDictEntry = calcsize('z2P') # sizeof(PyDictEntry) 226 _sizeof_Csetentry = calcsize('lP') # sizeof(setentry) 227 228 # XXX use sys.int_info.sizeof_digit in Python 3.1 229 try: # C typedef digit for multi-precision int (or long) 230 _sizeof_Cdigit = long.__itemsize__ 231 except NameError: # no long in Python 3.0 232 _sizeof_Cdigit = int.__itemsize__ 233 if _sizeof_Cdigit < 2: 234 raise AssertionError('sizeof(%s) bad: %d' % ('digit', _sizeof_Cdigit)) 235 236 try: # sizeof(unicode_char) 237 u = unicode('\0') 238 except NameError: # no unicode() in Python 3.0 239 u = '\0' 240 u = u.encode('unicode-internal') # see .../Lib/test/test_sys.py 241 _sizeof_Cunicode = len(u) 242 del u 243 if (1 << (_sizeof_Cunicode << 3)) <= sys.maxunicode: 244 raise AssertionError('sizeof(%s) bad: %d' % ('unicode', _sizeof_Cunicode)) 245 246 if hasattr(sys, 'maxsize'): # new in Python 2.6 247 Z = calcsize('Z') # check sizeof(size_t) 248 if (1 << (Z << 3)) <= sys.maxsize: 249 raise AssertionError('sizeof(%s) bad: %d' % ('size_t', Z)) 250 del Z 251 252 try: # size of GC header, sizeof(PyGC_Head) 253 import _testcapi as t 254 _sizeof_CPyGC_Head = t.SIZEOF_PYGC_HEAD # new in Python 2.6 255 except (ImportError, AttributeError): # sizeof(PyGC_Head) 256 # alignment should be to sizeof(long double) but there 257 # is no way to obtain that value, assume twice double 258 t = calcsize('2d') - 1 259 _sizeof_CPyGC_Head = (calcsize('2Pz') + t) & ~t 260 del t 261 262 # size of refcounts (Python debug build only) 263 if hasattr(sys, 'gettotalrefcount'): 264 _sizeof_Crefcounts = calcsize('2z') 265 else: 266 _sizeof_Crefcounts = 0 267 268 # some flags from .../Include/object.h 269 _Py_TPFLAGS_HEAPTYPE = 1 << 9 # Py_TPFLAGS_HEAPTYPE 270 _Py_TPFLAGS_HAVE_GC = 1 << 14 # Py_TPFLAGS_HAVE_GC 271 272 _Type_type = type(type) # == type and new-style class type 273 274 275 # compatibility functions for more uniform 276 # behavior across Python version 2.2 thu 3.0 277
278 -def _items(obj): # dict only
279 '''Return iter-/generator, preferably. 280 ''' 281 return getattr(obj, 'iteritems', obj.items)() 282
283 -def _keys(obj): # dict only
284 '''Return iter-/generator, preferably. 285 ''' 286 return getattr(obj, 'iterkeys', obj.keys)() 287
288 -def _values(obj): # dict only
289 '''Use iter-/generator, preferably. 290 ''' 291 return getattr(obj, 'itervalues', obj.values)() 292 293 try: # callable() builtin 294 _callable = callable 295 except NameError: # callable() removed in Python 3.0
296 - def _callable(obj):
297 '''Substitute for callable().''' 298 return hasattr(obj, '__call__')
299 300 try: # get 'all' current objects 301 from gc import get_objects as _getobjects 302 except ImportError:
303 - def _getobjects():
304 # modules first, globals and stack 305 # (may contain duplicate objects) 306 return tuple(_values(sys.modules)) + ( 307 globals(), stack(sys.getrecursionlimit()))
308 309 try: # get 'all' referents of objects 310 # note that gc.get_referents() 311 # returns () for dict...-iterators 312 from gc import get_referents as _getreferents 313 except ImportError: # no get_referents() in Python 2.2
314 - def _getreferents(unused):
315 return () # sorry, no refs
316 317 # sys.getsizeof() new in Python 2.6 318 _getsizeof = getattr(sys, 'getsizeof', None) 319 320 try: # str intern() 321 _intern = intern 322 except NameError: # no intern() in Python 3.0
323 - def _intern(val):
324 return val
325
326 -def _kwds(**kwds): # no dict(key=value, ...) in Python 2.2
327 '''Return name=value pairs as keywords dict. 328 ''' 329 return kwds 330 331 try: # sorted() builtin 332 _sorted = sorted 333 except NameError: # no sorted() in Python 2.2
334 - def _sorted(vals, reverse=False):
335 '''Partial substitute for missing sorted().''' 336 vals.sort() # inplace OK 337 if reverse: 338 vals.reverse() 339 return vals
340 341 try: # sum() builtin 342 _sum = sum 343 except NameError: # no sum() in Python 2.2
344 - def _sum(vals):
345 '''Partial substitute for missing sum().''' 346 s = 0 347 for v in vals: 348 s += v 349 return s
350 351 352 # private functions 353
354 -def _basicsize(t, base=0, heap=False, obj=None):
355 '''Get non-zero basicsize of type, 356 including the header sizes. 357 ''' 358 s = max(getattr(t, '__basicsize__', 0), base) 359 # include gc header size 360 if t != _Type_type: 361 h = getattr(t, '__flags__', 0) & _Py_TPFLAGS_HAVE_GC 362 elif heap: # type, allocated on heap 363 h = True 364 else: # None has no __flags__ attr 365 h = getattr(obj, '__flags__', 0) & _Py_TPFLAGS_HEAPTYPE 366 if h: 367 s += _sizeof_CPyGC_Head 368 # include reference counters 369 return s + _sizeof_Crefcounts
370
371 -def _derive_typedef(typ):
372 '''Return single, existing super type typedef or None. 373 ''' 374 v = [v for v in _values(_typedefs) if _issubclass(typ, v.type)] 375 if len(v) == 1: 376 return v[0] 377 return None
378
379 -def _dir2(obj, pref='', excl=(), slots=None, itor=''):
380 '''Return an attribute name, object 2-tuple for certain 381 attributes or for the '__slots__' attributes of the 382 given object, but not both. Any iterator referent 383 objects are returned with the given name if the 384 latter is non-empty. 385 ''' 386 if slots: # __slots__ attrs 387 if hasattr(obj, slots): 388 # collect all inherited __slots__ attrs 389 # from list, tuple, or dict __slots__, 390 # while removing any duplicate attrs 391 s = {} 392 for c in type(obj).mro(): 393 for a in getattr(c, slots, ()): 394 if hasattr(obj, a): 395 s.setdefault(a, getattr(obj, a)) 396 # assume __slots__ tuple/list 397 # is holding the attr values 398 yield slots, _Slots(s) # _keys(s) 399 for t in _items(s): 400 yield t # attr name, value 401 elif itor: # iterator referents 402 for o in obj: # iter(obj) 403 yield itor, o 404 else: # regular attrs 405 for a in dir(obj): 406 if a.startswith(pref) and a not in excl and hasattr(obj, a): 407 yield a, getattr(obj, a)
408
409 -def _infer_dict(obj):
410 '''Return True for likely dict object. 411 ''' 412 for ats in (('__len__', 'get', 'has_key', 'items', 'keys', 'values'), 413 ('__len__', 'get', 'has_key', 'iteritems', 'iterkeys', 'itervalues')): 414 for a in ats: # no all(<generator_expression>) in Python 2.2 415 if not _callable(getattr(obj, a, None)): 416 break 417 else: # all True 418 return True 419 return False
420
421 -def _isdictclass(obj):
422 '''Return True for known dict objects. 423 ''' 424 c = getattr(obj, '__class__', None) 425 return c and c.__name__ in _dict_classes.get(c.__module__, ())
426
427 -def _issubclass(sub, sup):
428 '''Safe issubclass(). 429 ''' 430 if sup is not object: 431 try: 432 return issubclass(sub, sup) 433 except TypeError: 434 pass 435 return False
436
437 -def _itemsize(t, item=0):
438 '''Get non-zero itemsize of type. 439 ''' 440 # replace zero value with default 441 return getattr(t, '__itemsize__', 0) or item
442
443 -def _kwdstr(**kwds):
444 '''Keyword arguments as a string. 445 ''' 446 return ', '.join(_sorted(['%s=%r' % kv for kv in _items(kwds)])) # [] for Python 2.2
447
448 -def _lengstr(obj):
449 '''Object length as a string. 450 ''' 451 n = leng(obj) 452 if n is None: # no len 453 r = '' 454 elif n > _len(obj): # extended 455 r = ' leng %d!' % n 456 else: 457 r = ' leng %d' % n 458 return r
459
460 -def _nameof(obj, dflt=''):
461 '''Return the name of an object. 462 ''' 463 return getattr(obj, '__name__', dflt)
464
465 -def _objs(objs, all=None, **unused):
466 '''Return the given or 'all' objects. 467 ''' 468 if all in (False, None): 469 t = objs or () 470 elif all is True: # 'all' objects 471 t = objs or _getobjects() 472 else: 473 raise ValueError('invalid option: %s=%r' % ('all', all)) 474 return t
475
476 -def _p100(part, total, prec=1):
477 '''Return percentage as string. 478 ''' 479 r = float(total) 480 if r: 481 r = part * 100.0 / r 482 return '%.*f%%' % (prec, r) 483 return 'n/a'
484
485 -def _plural(num):
486 '''Return 's' if plural. 487 ''' 488 if num == 1: 489 s = '' 490 else: 491 s = 's' 492 return s
493
494 -def _power2(n):
495 '''Find the next power of 2. 496 ''' 497 p2 = 16 498 while n > p2: 499 p2 += p2 500 return p2
501
502 -def _prepr(obj, clip=0):
503 '''Prettify and clip long repr() string. 504 ''' 505 return _repr(obj, clip=clip).strip('<>').replace("'", '') # remove <''>
506
507 -def _printf(fmt, *args, **print3opts):
508 '''Formatted print. 509 ''' 510 if print3opts: # like Python 3.0 511 f = print3opts.get('file', None) or sys.stdout 512 if args: 513 f.write(fmt % args) 514 else: 515 f.write(fmt) 516 f.write(print3opts.get('end', linesep)) 517 elif args: 518 print(fmt % args) 519 else: 520 print(fmt)
521
522 -def _refs(obj, named, *ats, **kwds):
523 '''Return specific attribute objects of an object. 524 ''' 525 if named: 526 for a in ats: # cf. inspect.getmembers() 527 if hasattr(obj, a): 528 yield _NamedRef(a, getattr(obj, a)) 529 if kwds: # kwds are _dir2() args 530 for a, o in _dir2(obj, **kwds): 531 yield _NamedRef(a, o) 532 else: 533 for a in ats: # cf. inspect.getmembers() 534 if hasattr(obj, a): 535 yield getattr(obj, a) 536 if kwds: # kwds are _dir2() args 537 for _, o in _dir2(obj, **kwds): 538 yield o
539
540 -def _repr(obj, clip=80):
541 '''Clip long repr() string. 542 ''' 543 try: # safe repr() 544 r = repr(obj) 545 except TypeError: 546 r = 'N/A' 547 if 0 < clip < len(r): 548 h = (clip // 2) - 2 549 if h > 0: 550 r = r[:h] + '....' + r[-h:] 551 return r
552
553 -def _SI(size, K=1024, i='i'):
554 '''Return size as SI string. 555 ''' 556 if 1 < K < size: 557 f = float(size) 558 for si in iter('KMGPTE'): 559 f /= K 560 if f < K: 561 return ' or %.1f %s%sB' % (f, si, i) 562 return ''
563
564 -def _SI2(size, **kwds):
565 '''Return size as regular plus SI string. 566 ''' 567 return str(size) + _SI(size, **kwds)
568 569 # type-specific referent functions 570
571 -def _class_refs(obj, named):
572 '''Return specific referents of a class object. 573 ''' 574 return _refs(obj, named, '__class__', '__dict__', '__doc__', '__mro__', 575 '__name__', '__slots__', '__weakref__')
576
577 -def _co_refs(obj, named):
578 '''Return specific referents of a code object. 579 ''' 580 return _refs(obj, named, pref='co_')
581
582 -def _dict_refs(obj, named):
583 '''Return key and value objects of a dict/proxy. 584 ''' 585 if named: 586 for k, v in _items(obj): 587 s = str(k) 588 yield _NamedRef(s, k, 1) # key 589 yield _NamedRef(s, v, 2) # value 590 else: 591 for k, v in _items(obj): 592 yield k 593 yield v
594
595 -def _enum_refs(obj, named):
596 '''Return specific referents of an enumerate object. 597 ''' 598 return _refs(obj, named, '__doc__')
599
600 -def _exc_refs(obj, named):
601 '''Return specific referents of an Exception object. 602 ''' 603 # .message raises DeprecationWarning in Python 2.6 604 return _refs(obj, named, 'args', 'filename', 'lineno', 'msg', 'text') # , 'message', 'mixed'
605
606 -def _file_refs(obj, named):
607 '''Return specific referents of a file object. 608 ''' 609 return _refs(obj, named, 'mode', 'name')
610
611 -def _frame_refs(obj, named):
612 '''Return specific referents of a frame object. 613 ''' 614 return _refs(obj, named, pref='f_')
615
616 -def _func_refs(obj, named):
617 '''Return specific referents of a function or lambda object. 618 ''' 619 return _refs(obj, named, '__doc__', '__name__', '__code__', 620 pref='func_', excl=('func_globals',))
621
622 -def _gen_refs(obj, named):
623 '''Return the referent(s) of a generator object. 624 ''' 625 # only some gi_frame attrs 626 f = getattr(obj, 'gi_frame', None) 627 return _refs(f, named, 'f_locals', 'f_code')
628
629 -def _im_refs(obj, named):
630 '''Return specific referents of a method object. 631 ''' 632 return _refs(obj, named, '__doc__', '__name__', '__code__', 633 pref='im_')
634
635 -def _inst_refs(obj, named):
636 '''Return specific referents of a class instance. 637 ''' 638 return _refs(obj, named, '__dict__', '__class__', 639 slots='__slots__')
640
641 -def _iter_refs(obj, named):
642 '''Return the referent(s) of an iterator object. 643 ''' 644 r = _getreferents(obj) # special case 645 return _refs(r, named, itor=_nameof(obj) or 'iteref')
646
647 -def _module_refs(obj, named):
648 '''Return specific referents of a module object. 649 ''' 650 # ignore this very module 651 if obj.__name__ == __name__: 652 return () 653 # module is essentially a dict 654 return _dict_refs(obj.__dict__, named)
655
656 -def _prop_refs(obj, named):
657 '''Return specific referents of a property object. 658 ''' 659 return _refs(obj, named, '__doc__', pref='f')
660
661 -def _seq_refs(obj, unused): # named unused for PyChecker
662 '''Return specific referents of a frozen/set, list, tuple and xrange object. 663 ''' 664 return obj # XXX for r in obj: yield r 665
666 -def _stat_refs(obj, named):
667 '''Return referents of a os.stat object. 668 ''' 669 return _refs(obj, named, pref='st_')
670
671 -def _statvfs_refs(obj, named):
672 '''Return referents of a os.statvfs object. 673 ''' 674 return _refs(obj, named, pref='f_')
675
676 -def _tb_refs(obj, named):
677 '''Return specific referents of a traceback object. 678 ''' 679 return _refs(obj, named, pref='tb_')
680
681 -def _type_refs(obj, named):
682 '''Return specific referents of a type object. 683 ''' 684 return _refs(obj, named, '__dict__', '__doc__', '__mro__', 685 '__name__', '__slots__', '__weakref__')
686
687 -def _weak_refs(obj, unused): # named unused for PyChecker
688 '''Return weakly referent object. 689 ''' 690 try: # ignore 'key' of KeyedRef 691 return (obj(),) 692 except: # XXX ReferenceError 693 return () #PYCHOK OK 694 695 _all_refs = (None, _class_refs, _co_refs, _dict_refs, _enum_refs, 696 _exc_refs, _file_refs, _frame_refs, _func_refs, 697 _gen_refs, _im_refs, _inst_refs, _iter_refs, 698 _module_refs, _prop_refs, _seq_refs, _stat_refs, 699 _statvfs_refs, _tb_refs, _type_refs, _weak_refs) 700 701 702 # type-specific length functions 703
704 -def _len(obj):
705 '''Safe len(). 706 ''' 707 try: 708 return len(obj) 709 except TypeError: # no len() 710 return 0
711
712 -def _len_array(obj):
713 '''Array length in bytes. 714 ''' 715 return len(obj) * obj.itemsize
716
717 -def _len_bytearray(obj):
718 '''Bytearray size. 719 ''' 720 return obj.__alloc__()
721
722 -def _len_code(obj): # see .../Lib/test/test_sys.py
723 '''Length of code object (stack and variables only). 724 ''' 725 return obj.co_stacksize + obj.co_nlocals \ 726 + _len(obj.co_freevars) \ 727 + _len(obj.co_cellvars) - 1 728
729 -def _len_dict(obj):
730 '''Dict length in items (estimate). 731 ''' 732 n = len(obj) # active items 733 if n < 6: # ma_smalltable ... 734 n = 0 # ... in basicsize 735 else: # at least one unused 736 n = _power2(n + 1) 737 return n
738
739 -def _len_frame(obj):
740 '''Length of a frame object. 741 ''' 742 c = getattr(obj, 'f_code', None) 743 if c: 744 n = _len_code(c) 745 else: 746 n = 0 747 return n
748 749 _digit2p2 = 1 << (_sizeof_Cdigit << 3) 750 _digitmax = _digit2p2 - 1 # == (2 * PyLong_MASK + 1) 751 _digitlog = 1.0 / log(_digit2p2) 752
753 -def _len_int(obj):
754 '''Length of multi-precision int (aka long) in digits. 755 ''' 756 if obj: 757 n, i = 1, abs(obj) 758 if i > _digitmax: 759 # no log(x[, base]) in Python 2.2 760 n += int(log(i) * _digitlog) 761 else: # zero 762 n = 0 763 return n
764
765 -def _len_iter(obj):
766 '''Length (hint) of an iterator. 767 ''' 768 n = getattr(obj, '__length_hint__', None) 769 if n: 770 n = n() 771 else: # try len() 772 n = _len(obj) 773 return n
774
775 -def _len_list(obj):
776 '''Length of list (estimate). 777 ''' 778 n = len(obj) 779 # estimate over-allocation 780 if n > 8: 781 n += 6 + (n >> 3) 782 elif n: 783 n += 4 784 return n
785
786 -def _len_module(obj):
787 '''Module length. 788 ''' 789 return _len(obj.__dict__) # _len(dir(obj))
790
791 -def _len_set(obj):
792 '''Length of frozen/set (estimate). 793 ''' 794 n = len(obj) 795 if n > 8: # assume half filled 796 n = _power2(n + n - 2) 797 elif n: # at least 8 798 n = 8 799 return n
800
801 -def _len_slice(obj):
802 '''Slice length. 803 ''' 804 try: 805 return ((obj.stop - obj.start + 1) // obj.step) 806 except (AttributeError, TypeError): 807 return 0
808
809 -def _len_slots(obj):
810 '''Slots length. 811 ''' 812 return len(obj) - 1
813
814 -def _len_struct(obj):
815 '''Struct length in bytes. 816 ''' 817 try: 818 return obj.size 819 except AttributeError: 820 return 0
821
822 -def _len_unicode(obj):
823 '''Unicode size. 824 ''' 825 return len(obj) + 1
826 827 _all_lengs = (None, _len, _len_array, _len_bytearray, 828 _len_code, _len_dict, _len_frame, 829 _len_int, _len_iter, _len_list, 830 _len_module, _len_set, _len_slice, 831 _len_slots, _len_struct, _len_unicode) 832 833 834 # more private functions and classes 835 836 _old_style = '*' # marker 837 _new_style = '' # no marker 838
839 -class _Claskey(object):
840 '''Wrapper for class objects. 841 ''' 842 __slots__ = ('_obj', '_sty') 843
844 - def __init__(self, obj, style):
845 self._obj = obj # XXX Weakref.ref(obj) 846 self._sty = style
847
848 - def __str__(self):
849 r = str(self._obj) 850 if r.endswith('>'): 851 r = '%s%s def>' % (r[:-1], self._sty) 852 elif self._sty is _old_style and not r.startswith('class '): 853 r = 'class %s%s def' % (r, self._sty) 854 else: 855 r = '%s%s def' % (r, self._sty) 856 return r
857 __repr__ = __str__
858 859 # For most objects, the object type is used as the key in the 860 # _typedefs dict further below, except class and type objects 861 # and old-style instances. Those are wrapped with separate 862 # _Claskey or _Instkey instances to be able (1) to distinguish 863 # instances of different old-style classes by class, (2) to 864 # distinguish class (and type) instances from class (and type) 865 # definitions for new-style classes and (3) provide similar 866 # results for repr() and str() of new- and old-style classes 867 # and instances. 868 869 _claskeys = {} # [id(obj)] = _Claskey() 870
871 -def _claskey(obj, style):
872 '''Wrap an old- or new-style class object. 873 ''' 874 i = id(obj) 875 k = _claskeys.get(i, None) 876 if not k: 877 _claskeys[i] = k = _Claskey(obj, style) 878 return k
879 880 try: # no Class- and InstanceType in Python 3.0 881 _Types_ClassType = Types.ClassType 882 _Types_InstanceType = Types.InstanceType 883
884 - class _Instkey(object):
885 '''Wrapper for old-style class (instances). 886 ''' 887 __slots__ = ('_obj',) 888
889 - def __init__(self, obj):
890 self._obj = obj # XXX Weakref.ref(obj)
891
892 - def __str__(self):
893 return '<class %s.%s%s>' % (self._obj.__module__, self._obj.__name__, _old_style)
894 __repr__ = __str__
895 896 _instkeys = {} # [id(obj)] = _Instkey() 897
898 - def _instkey(obj):
899 '''Wrap an old-style class (instance). 900 ''' 901 i = id(obj) 902 k = _instkeys.get(i, None) 903 if not k: 904 _instkeys[i] = k = _Instkey(obj) 905 return k
906
907 - def _keytuple(obj):
908 '''Return class and instance keys for a class. 909 ''' 910 t = type(obj) 911 if t is _Types_InstanceType: 912 t = obj.__class__ 913 return _claskey(t, _old_style), _instkey(t) 914 elif t is _Types_ClassType: 915 return _claskey(obj, _old_style), _instkey(obj) 916 elif t is _Type_type: 917 return _claskey(obj, _new_style), obj 918 return None, None # not a class
919
920 - def _objkey(obj):
921 '''Return the key for any object. 922 ''' 923 k = type(obj) 924 if k is _Types_InstanceType: 925 k = _instkey(obj.__class__) 926 elif k is _Types_ClassType: 927 k = _claskey(obj, _old_style) 928 elif k is _Type_type: 929 k = _claskey(obj, _new_style) 930 return k
931 932 except AttributeError: # Python 3.0 933
934 - def _keytuple(obj): #PYCHOK expected
935 '''Return class and instance keys for a class. 936 ''' 937 if type(obj) is _Type_type: # isclass(obj): 938 return _claskey(obj, _new_style), obj 939 return None, None # not a class 940
941 - def _objkey(obj): #PYCHOK expected
942 '''Return the key for any object. 943 ''' 944 k = type(obj) 945 if k is _Type_type: # isclass(obj): 946 k = _claskey(obj, _new_style) 947 return k 948
949 -class _NamedRef(object):
950 '''Store referred object along 951 with the name of the referent. 952 ''' 953 __slots__ = ('name', 'ref', 'typ') 954
955 - def __init__(self, name, ref, typ=0):
956 self.name = name 957 self.ref = ref 958 self.typ = typ # see Asized.format
959
960 -class _Slots(tuple):
961 '''Wrapper class for __slots__ attribute at 962 class instances to account for the size 963 of the __slots__ tuple/list containing 964 references to the attribute values. 965 ''' 966 pass
967 968 # kinds of _Typedefs 969 _i = _intern 970 _all_kinds = (_kind_static, _kind_dynamic, _kind_derived, _kind_ignored, _kind_inferred) = ( 971 _i('static'), _i('dynamic'), _i('derived'), _i('ignored'), _i('inferred')) 972 del _i 973
974 -class _Typedef(object):
975 '''Type definition class. 976 ''' 977 __slots__ = { 978 'base': 0, # basic size in bytes 979 'item': 0, # item size in bytes 980 'leng': None, # or _len_...() function 981 'refs': None, # or _..._refs() function 982 'both': None, # both data and code if True, code only if False 983 'kind': None, # _kind_... value 984 'type': None} # original type 985
986 - def __init__(self, **kwds):
987 self.reset(**kwds)
988
989 - def __lt__(self, unused): # for Python 3.0
990 return True
991
992 - def __repr__(self):
993 return repr(self.args())
994
995 - def __str__(self):
996 t = [str(self.base), str(self.item)] 997 for f in (self.leng, self.refs): 998 if f: 999 t.append(f.__name__) 1000 else: 1001 t.append('n/a') 1002 if not self.both: 1003 t.append('(code only)') 1004 return ', '.join(t)
1005
1006 - def args(self): # as args tuple
1007 '''Return all attributes as arguments tuple. 1008 ''' 1009 return (self.base, self.item, self.leng, self.refs, 1010 self.both, self.kind, self.type) 1011
1012 - def dup(self, other=None, **kwds):
1013 '''Duplicate attributes of dict or other typedef. 1014 ''' 1015 if other is None: 1016 d = _dict_typedef.kwds() 1017 else: 1018 d = other.kwds() 1019 d.update(kwds) 1020 self.reset(**d)
1021
1022 - def flat(self, obj, mask=0):
1023 '''Return the aligned flat size. 1024 ''' 1025 s = self.base 1026 if self.leng and self.item > 0: # include items 1027 s += self.leng(obj) * self.item 1028 if _getsizeof: # _getsizeof prevails 1029 s = _getsizeof(obj, s) 1030 if mask: # align 1031 s = (s + mask) & ~mask 1032 return s
1033
1034 - def format(self):
1035 '''Return format dict. 1036 ''' 1037 c = n = '' 1038 if not self.both: 1039 c = ' (code only)' 1040 if self.leng: 1041 n = ' (%s)' % _nameof(self.leng) 1042 return _kwds(base=self.base, item=self.item, leng=n, 1043 code=c, kind=self.kind)
1044
1045 - def kwds(self):
1046 '''Return all attributes as keywords dict. 1047 ''' 1048 # no dict(refs=self.refs, ..., kind=self.kind) in Python 2.0 1049 return _kwds(base=self.base, item=self.item, 1050 leng=self.leng, refs=self.refs, 1051 both=self.both, kind=self.kind, type=self.type)
1052
1053 - def save(self, t, base=0, heap=False):
1054 '''Save this typedef plus its class typedef. 1055 ''' 1056 c, k = _keytuple(t) 1057 if k and k not in _typedefs: # instance key 1058 _typedefs[k] = self 1059 if c and c not in _typedefs: # class key 1060 if t.__module__ in _builtin_modules: 1061 k = _kind_ignored # default 1062 else: 1063 k = self.kind 1064 _typedefs[c] = _Typedef(base=_basicsize(type(t), base=base, heap=heap), 1065 refs=_type_refs, 1066 both=False, kind=k, type=t) 1067 elif isbuiltin(t) and t not in _typedefs: # array, range, xrange in Python 2.x 1068 _typedefs[t] = _Typedef(base=_basicsize(t, base=base), 1069 both=False, kind=_kind_ignored, type=t) 1070 else: 1071 raise KeyError('asizeof typedef %r bad: %r %r' % (self, (c, k), self.both))
1072
1073 - def set(self, safe_len=False, **kwds):
1074 '''Set one or more attributes. 1075 ''' 1076 if kwds: # double check 1077 d = self.kwds() 1078 d.update(kwds) 1079 self.reset(**d) 1080 if safe_len and self.item: 1081 self.leng = _len
1082
1083 - def reset(self, base=0, item=0, leng=None, refs=None, 1084 both=True, kind=None, type=None):
1085 '''Reset all specified attributes. 1086 ''' 1087 if base < 0: 1088 raise ValueError('invalid option: %s=%r' % ('base', base)) 1089 else: 1090 self.base = base 1091 if item < 0: 1092 raise ValueError('invalid option: %s=%r' % ('item', item)) 1093 else: 1094 self.item = item 1095 if leng in _all_lengs: # XXX or _callable(leng) 1096 self.leng = leng 1097 else: 1098 raise ValueError('invalid option: %s=%r' % ('leng', leng)) 1099 if refs in _all_refs: # XXX or _callable(refs) 1100 self.refs = refs 1101 else: 1102 raise ValueError('invalid option: %s=%r' % ('refs', refs)) 1103 if both in (False, True): 1104 self.both = both 1105 else: 1106 raise ValueError('invalid option: %s=%r' % ('both', both)) 1107 if kind in _all_kinds: 1108 self.kind = kind 1109 else: 1110 raise ValueError('invalid option: %s=%r' % ('kind', kind)) 1111 self.type = type
1112 1113 _typedefs = {} # [key] = _Typedef() 1114
1115 -def _typedef_both(t, base=0, item=0, leng=None, refs=None, kind=_kind_static, heap=False):
1116 '''Add new typedef for both data and code. 1117 ''' 1118 v = _Typedef(base=_basicsize(t, base=base), item=_itemsize(t, item), 1119 refs=refs, leng=leng, 1120 both=True, kind=kind, type=t) 1121 v.save(t, base=base, heap=heap) 1122 return v # for _dict_typedef
1123
1124 -def _typedef_code(t, base=0, refs=None, kind=_kind_static, heap=False):
1125 '''Add new typedef for code only. 1126 ''' 1127 v = _Typedef(base=_basicsize(t, base=base), 1128 refs=refs, 1129 both=False, kind=kind, type=t) 1130 v.save(t, base=base, heap=heap) 1131 return v # for _dict_typedef
1132 1133 # static typedefs for data and code types 1134 _typedef_both(complex) 1135 _typedef_both(float) 1136 _typedef_both(list, refs=_seq_refs, leng=_len_list, item=_sizeof_Cvoidp) # sizeof(PyObject*) 1137 _typedef_both(tuple, refs=_seq_refs, leng=_len, item=_sizeof_Cvoidp) # sizeof(PyObject*) 1138 _typedef_both(property, refs=_prop_refs) 1139 _typedef_both(type(Ellipsis)) 1140 _typedef_both(type(None)) 1141 1142 # _Slots is a special tuple, see _Slots.__doc__ 1143 _typedef_both(_Slots, item=_sizeof_Cvoidp, 1144 leng=_len_slots, # length less one 1145 refs=None, # but no referents 1146 heap=True) # plus head 1147 1148 # dict, dictproxy, dict_proxy and other dict-like types 1149 _dict_typedef = _typedef_both(dict, item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs) 1150 try: # <type dictproxy> only in Python 2.x 1151 _typedef_both(Types.DictProxyType, item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs) 1152 except AttributeError: # XXX any class __dict__ is <type dict_proxy> in Python 3.0? 1153 _typedef_both(type(_Typedef.__dict__), item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs) 1154 # other dict-like classes and types may be derived or inferred, 1155 # provided the module and class name is listed here (see functions 1156 # adict, _isdictclass and _infer_dict for further details) 1157 _dict_classes = {'UserDict': ('IterableUserDict', 'UserDict'), 1158 'weakref' : ('WeakKeyDictionary', 'WeakValueDictionary')} 1159 try: # <type module> is essentially a dict 1160 _typedef_both(Types.ModuleType, base=_dict_typedef.base, 1161 item=_dict_typedef.item + _sizeof_CPyModuleObject, 1162 leng=_len_module, refs=_module_refs) 1163 except AttributeError: # missing 1164 pass 1165 1166 # newer or obsolete types 1167 try: 1168 from array import array # array type 1169 _typedef_both(array, leng=_len_array, item=_sizeof_Cbyte) 1170 except ImportError: # missing 1171 pass 1172 1173 try: # bool has non-zero __itemsize__ in 3.0 1174 _typedef_both(bool) 1175 except NameError: # missing 1176 pass 1177 1178 try: # ignore basestring 1179 _typedef_both(basestring, leng=None) 1180 except NameError: # missing 1181 pass 1182 1183 try: 1184 if isbuiltin(buffer): # Python 2.2 1185 _typedef_both(type(buffer('')), item=_sizeof_Cbyte, leng=_len) # XXX len in bytes? 1186 else: 1187 _typedef_both(buffer, item=_sizeof_Cbyte, leng=_len) # XXX len in bytes? 1188 except NameError: # missing 1189 pass 1190 1191 try: 1192 _typedef_both(bytearray, item=_sizeof_Cbyte, leng=_len_bytearray) #PYCHOK bytearray new in 2.6, 3.0 1193 except NameError: # missing 1194 pass 1195 try: 1196 if type(bytes) is not type(str): # bytes is str in 2.6 #PYCHOK bytes new in 2.6, 3.0 1197 _typedef_both(bytes, item=_sizeof_Cbyte, leng=_len) #PYCHOK bytes new in 2.6, 3.0 1198 except NameError: # missing 1199 pass 1200 try: # XXX like bytes 1201 _typedef_both(str8, item=_sizeof_Cbyte, leng=_len) #PYCHOK str8 new in 2.6, 3.0 1202 except NameError: # missing 1203 pass 1204 1205 try: 1206 _typedef_both(enumerate, refs=_enum_refs) 1207 except NameError: # missing 1208 pass 1209 1210 try: # Exception is type in Python 3.0 1211 _typedef_both(Exception, refs=_exc_refs) 1212 except: # missing 1213 pass #PYCHOK OK 1214 1215 try: 1216 _typedef_both(file, refs=_file_refs) 1217 except NameError: # missing 1218 pass 1219 1220 try: 1221 _typedef_both(frozenset, item=_sizeof_Csetentry, leng=_len_set, refs=_seq_refs) 1222 except NameError: # missing 1223 pass 1224 try: 1225 _typedef_both(set, item=_sizeof_Csetentry, leng=_len_set, refs=_seq_refs) 1226 except NameError: # missing 1227 pass 1228 1229 try: # not callable() 1230 _typedef_both(Types.GetSetDescriptorType) 1231 except AttributeError: # missing 1232 pass 1233 1234 try: # if long exists, it is multi-precision ... 1235 _typedef_both(long, item=_sizeof_Cdigit, leng=_len_int) 1236 _typedef_both(int) # ... and int is fixed size 1237 except NameError: # no long, only multi-precision int in Python 3.0 1238 _typedef_both(int, item=_sizeof_Cdigit, leng=_len_int) 1239 1240 try: # not callable() 1241 _typedef_both(Types.MemberDescriptorType) 1242 except AttributeError: # missing 1243 pass 1244 1245 try: 1246 _typedef_both(type(NotImplemented)) # == Types.NotImplementedType 1247 except NameError: # missing 1248 pass 1249 1250 try: 1251 _typedef_both(range) 1252 except NameError: # missing 1253 pass 1254 try: 1255 _typedef_both(xrange) 1256 except NameError: # missing 1257 pass 1258 1259 try: 1260 _typedef_both(reversed, refs=_enum_refs) 1261 except NameError: # missing 1262 pass 1263 1264 try: 1265 _typedef_both(slice, item=_sizeof_Cvoidp, leng=_len_slice) # XXX worst-case itemsize? 1266 except NameError: # missing 1267 pass 1268 1269 try: 1270 from os import curdir, stat, statvfs 1271 _typedef_both(type(stat( curdir)), refs=_stat_refs) # stat_result 1272 _typedef_both(type(statvfs(curdir)), refs=_statvfs_refs, # statvfs_result 1273 item=_sizeof_Cvoidp, leng=_len) 1274 except ImportError: # missing 1275 pass 1276 1277 try: 1278 from struct import Struct # only in Python 2.5 and 3.0 1279 _typedef_both(Struct, item=_sizeof_Cbyte, leng=_len_struct) # len in bytes 1280 except ImportError: # missing 1281 pass 1282 1283 try: 1284 _typedef_both(Types.TracebackType, refs=_tb_refs) 1285 except AttributeError: # missing 1286 pass 1287 1288 try: 1289 _typedef_both(unicode, leng=_len_unicode, item=_sizeof_Cunicode) 1290 _typedef_both(str, leng=_len, item=_sizeof_Cbyte) # 1-byte char 1291 except NameError: # str is unicode 1292 _typedef_both(str, leng=_len_unicode, item=_sizeof_Cunicode) 1293 1294 try: # <type 'KeyedRef'> 1295 _typedef_both(Weakref.KeyedRef, refs=_weak_refs, heap=True) # plus head 1296 except AttributeError: # missing 1297 pass 1298 1299 try: # <type 'weakproxy'> 1300 _typedef_both(Weakref.ProxyType) 1301 except AttributeError: # missing 1302 pass 1303 1304 try: # <type 'weakref'> 1305 _typedef_both(Weakref.ReferenceType, refs=_weak_refs) 1306 except AttributeError: # missing 1307 pass 1308 1309 # some other, callable types 1310 _typedef_code(object, kind=_kind_ignored) 1311 _typedef_code(super, kind=_kind_ignored) 1312 _typedef_code(_Type_type, kind=_kind_ignored) 1313 1314 try: 1315 _typedef_code(classmethod, refs=_im_refs) 1316 except NameError: 1317 pass 1318 try: 1319 _typedef_code(staticmethod, refs=_im_refs) 1320 except NameError: 1321 pass 1322 try: 1323 _typedef_code(Types.MethodType, refs=_im_refs) 1324 except NameError: 1325 pass 1326 1327 try: # generator, code only, no len(), not callable() 1328 _typedef_code(Types.GeneratorType, refs=_gen_refs) 1329 except AttributeError: # missing 1330 pass 1331 1332 try: # <type 'weakcallableproxy'> 1333 _typedef_code(Weakref.CallableProxyType, refs=_weak_refs) 1334 except AttributeError: # missing 1335 pass 1336 1337 # any type-specific iterators 1338 s = [_items({}), _keys({}), _values({})] 1339 try: # reversed list and tuples iterators 1340 s.extend([reversed([]), reversed(())]) 1341 except NameError: # missing 1342 pass 1343 try: # range iterator 1344 s.append(xrange(1)) 1345 except NameError: # missing 1346 pass 1347 try: # callable-iterator 1348 from re import finditer 1349 s.append(finditer('', '')) 1350 except ImportError: # missing 1351 pass 1352 for t in _values(_typedefs): 1353 if t.type and t.leng: 1354 try: # create an (empty) instance 1355 s.append(t.type()) 1356 except TypeError: 1357 pass 1358 for t in s: 1359 try: 1360 i = iter(t) 1361 _typedef_both(type(i), leng=_len_iter, refs=_iter_refs, item=0) # no itemsize! 1362 except (KeyError, TypeError): # ignore non-iterables, duplicates, etc. 1363 pass 1364 del i, s, t 1365 1366
1367 -def _typedef(obj, derive=False, infer=False):
1368 '''Create a new typedef for an object. 1369 ''' 1370 t = type(obj) 1371 v = _Typedef(base=_basicsize(t, obj=obj), 1372 kind=_kind_dynamic, type=t) 1373 ##_printf('new %r %r/%r %s', t, _basicsize(t), _itemsize(t), _repr(dir(obj))) 1374 if ismodule(obj): # handle module like dict 1375 v.dup(item=_dict_typedef.item + _sizeof_CPyModuleObject, 1376 leng=_len_module, 1377 refs=_module_refs) 1378 elif isframe(obj): 1379 v.set(base=_basicsize(t, base=_sizeof_CPyFrameObject, obj=obj), 1380 item=_itemsize(t), 1381 leng=_len_frame, 1382 refs=_frame_refs) 1383 elif iscode(obj): 1384 v.set(base=_basicsize(t, base=_sizeof_CPyCodeObject, obj=obj), 1385 item=_sizeof_Cvoidp, 1386 leng=_len_code, 1387 refs=_co_refs, 1388 both=False) # code only 1389 elif _callable(obj): 1390 if isclass(obj): # class or type 1391 v.set(refs=_class_refs, 1392 both=False) # code only 1393 if obj.__module__ in _builtin_modules: 1394 v.set(kind=_kind_ignored) 1395 elif isbuiltin(obj): # function or method 1396 v.set(both=False, # code only 1397 kind=_kind_ignored) 1398 elif isfunction(obj): 1399 v.set(refs=_func_refs, 1400 both=False) # code only 1401 elif ismethod(obj): 1402 v.set(refs=_im_refs, 1403 both=False) # code only 1404 elif isclass(t): # callable instance, e.g. SCons, 1405 # handle like any other instance further below 1406 v.set(item=_itemsize(t), safe_len=True, 1407 refs=_inst_refs) # not code only! 1408 else: 1409 v.set(both=False) # code only 1410 elif _issubclass(t, dict): 1411 v.dup(kind=_kind_derived) 1412 elif _isdictclass(obj) or (infer and _infer_dict(obj)): 1413 v.dup(kind=_kind_inferred) 1414 elif getattr(obj, '__module__', None) in _builtin_modules: 1415 v.set(kind=_kind_ignored) 1416 else: # assume an instance of some class 1417 if derive: 1418 p = _derive_typedef(t) 1419 if p: # duplicate parent 1420 v.dup(other=p, kind=_kind_derived) 1421 return v 1422 if _issubclass(t, Exception): 1423 v.set(item=_itemsize(t), safe_len=True, 1424 refs=_exc_refs, 1425 kind=_kind_derived) 1426 elif isinstance(obj, Exception): 1427 v.set(item=_itemsize(t), safe_len=True, 1428 refs=_exc_refs) 1429 else: 1430 v.set(item=_itemsize(t), safe_len=True, 1431 refs=_inst_refs) 1432 return v
1433 1434
1435 -class _Prof(object):
1436 '''Internal type profile class. 1437 ''' 1438 total = 0 # total size 1439 high = 0 # largest size 1440 number = 0 # number of (unique) objects 1441 objref = None # largest object (weakref) 1442 weak = False # objref is weakref(object) 1443
1444 - def __cmp__(self, other):
1445 if self.total < other.total: 1446 return -1 1447 if self.total > other.total: 1448 return +1 1449 if self.number < other.number: 1450 return -1 1451 if self.number > other.number: 1452 return +1 1453 return 0
1454
1455 - def __lt__(self, other): # for Python 3.0
1456 return self.__cmp__(other) < 0
1457
1458 - def format(self, clip=0, grand=None):
1459 '''Return format dict. 1460 ''' 1461 if self.number > 1: # avg., plural 1462 a, p = int(self.total / self.number), 's' 1463 else: 1464 a, p = self.total, '' 1465 o = self.objref 1466 if self.weak: # weakref'd 1467 o = o() 1468 t = _SI2(self.total) 1469 if grand: 1470 t += ' (%s)' % _p100(self.total, grand, prec=0) 1471 return _kwds(avg=_SI2(a), high=_SI2(self.high), 1472 lengstr=_lengstr(o), obj=_repr(o, clip=clip), 1473 plural=p, total=t)
1474
1475 - def update(self, obj, size):
1476 '''Update this profile. 1477 ''' 1478 self.number += 1 1479 self.total += size 1480 if self.high < size: # largest 1481 self.high = size 1482 try: # prefer using weak ref 1483 self.objref, self.weak = Weakref.ref(obj), True 1484 except TypeError: 1485 self.objref, self.weak = obj, False
1486 1487 1488 # public classes 1489
1490 -class Asized(object):
1491 '''Store the results of an asized object 1492 in these 4 attributes: 1493 1494 size - total size of the object 1495 flat - flat size of the object 1496 name - name or repr of the object 1497 refs - tuple containing an instance 1498 of Asized for each referent 1499 ''' 1500 strf = ( '%s', # default name format 1501 '[K] %s', # dict key, see _dict_refs 1502 '[V] %s') # dict value, see _dict_refs 1503
1504 - def __init__(self, size, flat, refs=(), name=None):
1505 self.size = size # total size 1506 self.flat = flat # flat size 1507 self.name = name # name, repr or None 1508 self.refs = tuple(refs)
1509
1510 - def __str__(self):
1511 return 'size %r, flat %r, refs[%d], name %r' % ( 1512 self.size, self.flat, len(self.refs), self.name)
1513
1514 - def format(self, named):
1515 '''Format name from _NamedRef instance. 1516 ''' 1517 return self.strf[named.typ] % named.name
1518
1519 -class Asizer(object):
1520 '''Sizer state and options. 1521 ''' 1522 _align_ = 8 1523 _all_ = False 1524 _clip_ = 80 1525 _code_ = False 1526 _derive_ = False 1527 _detail_ = 0 # for Asized only 1528 _infer_ = False 1529 _limit_ = 100 1530 _stats_ = 0 1531 1532 _cutoff = 0 # in percent 1533 _depth = 0 # recursion depth 1534 _duplicate = 0 1535 _excl_d = None # {} 1536 _ign_d = _kind_ignored 1537 _incl = '' # or ' (incl. code)' 1538 _mask = 7 # see _align_ 1539 _missed = 0 # due to errors 1540 _profile = False 1541 _profs = None # {} 1542 _seen = None # {} 1543 _total = 0 # total size 1544
1545 - def __init__(self, **opts):
1546 '''See method reset for the available options. 1547 ''' 1548 self._excl_d = {} 1549 self.reset(**opts)
1550
1551 - def _clear(self):
1552 '''Clear state. 1553 ''' 1554 self._all_ = False 1555 self._depth = 0 # recursion depth 1556 self._duplicate = 0 1557 self._incl = '' # or ' (incl. code)' 1558 self._missed = 0 # due to errors 1559 self._profile = False 1560 self._profs = {} 1561 self._seen = {} 1562 self._total = 0 # total size 1563 for k in _keys(self._excl_d): 1564 self._excl_d[k] = 0
1565
1566 - def _nameof(self, obj):
1567 '''Return the object's name. 1568 ''' 1569 return _nameof(obj, '') or self._repr(obj)
1570
1571 - def _prepr(self, obj):
1572 '''Like prepr(). 1573 ''' 1574 return _prepr(obj, clip=self._clip_)
1575
1576 - def _prof(self, key):
1577 '''Get _Prof object. 1578 ''' 1579 p = self._profs.get(key, None) 1580 if not p: 1581 self._profs[key] = p = _Prof() 1582 return p
1583
1584 - def _repr(self, obj):
1585 '''Like repr(). 1586 ''' 1587 return _repr(obj, clip=self._clip_)
1588
1589 - def _sizer(self, obj, deep, sized):
1590 '''Size an object, recursively. 1591 ''' 1592 s, f, i = 0, 0, id(obj) 1593 # skip obj if seen before 1594 # or if ref of a given obj 1595 if i in self._seen: 1596 if deep: 1597 self._seen[i] += 1 1598 if sized: 1599 s = sized(s, f, name=self._nameof(obj)) 1600 return s 1601 else: 1602 self._seen[i] = 0 1603 try: 1604 k, rs = _objkey(obj), [] 1605 if k in self._excl_d: 1606 self._excl_d[k] += 1 1607 else: 1608 v = _typedefs.get(k, None) 1609 if not v: # new typedef 1610 _typedefs[k] = v = _typedef(obj, derive=self._derive_, 1611 infer=self._infer_) 1612 if (v.both or self._code_) and v.kind is not self._ign_d: 1613 s = f = v.flat(obj, self._mask) # flat size 1614 if self._profile: # profile type 1615 self._prof(k).update(obj, s) 1616 # recurse, but not for nested modules 1617 if deep < self._limit_ and not (deep and ismodule(obj)): 1618 # add sizes of referents 1619 r, z, d = v.refs, self._sizer, deep + 1 1620 if self._all_: # use 'all' referents 1621 r = _getreferents(obj) 1622 if r: 1623 t = id(r) 1624 if t in self._seen: 1625 for o in r: # no sum(<generator_expression>) in Python 2.2 1626 s += z(o, d, None) 1627 else: # exclude container 1628 self._seen[t] = 0 1629 for o in r: # no sum(<generator_expression>) in Python 2.2 1630 s += z(o, d, None) 1631 del self._seen[t] 1632 elif r: # and _callable(r): 1633 if sized and deep < self._detail_: 1634 # use named referents 1635 for o in r(obj, True): 1636 if isinstance(o, _NamedRef): 1637 t = z(o.ref, d, sized) 1638 t.name = t.format(o) 1639 else: 1640 t = z(o, d, sized) 1641 t.name = self._nameof(o) 1642 rs.append(t) 1643 s += t.size 1644 else: # no sum(<generator_expression>) in Python 2.2 1645 for o in r(obj, False): 1646 s += z(o, d, None) 1647 # recursion depth 1648 if self._depth < d: 1649 self._depth = d 1650 self._seen[i] += 1 1651 except RuntimeError: # XXX RecursionLimitExceeded: 1652 self._missed += 1 1653 if sized: 1654 s = sized(s, f, name=self._nameof(obj), refs=rs) 1655 return s
1656
1657 - def _sizes(self, objs, sized=None):
1658 '''Return the size or an Asized instance for each 1659 given object and the total size. The total 1660 includes the size of duplicates only once. 1661 ''' 1662 self.exclude_refs(*objs) # skip refs to objs 1663 s, t = {}, [] 1664 for o in objs: 1665 i = id(o) 1666 if i in s: # duplicate 1667 self._seen[i] += 1 1668 self._duplicate += 1 1669 else: 1670 s[i] = self._sizer(o, 0, sized) 1671 t.append(s[i]) 1672 if sized: 1673 s = _sum([i.size for i in _values(s)]) # [] for Python 2.2 1674 else: 1675 s = _sum(_values(s)) 1676 self._total += s # accumulate 1677 return s, tuple(t)
1678
1679 - def asized(self, *objs, **opts):
1680 '''Size each object and return an Asized instance with 1681 size information and referents up to the given detail 1682 level (and with modified options, see method set). 1683 1684 If only one object is given, the return value is the 1685 Asized instance for that object. 1686 ''' 1687 if opts: 1688 self.set(**opts) 1689 if self._all_: 1690 raise KeyError('invalid option: %s=%r' % ('all', self._all_)) 1691 _, t = self._sizes(objs, Asized) 1692 if len(t) == 1: 1693 t = t[0] 1694 return t
1695
1696 - def asizeof(self, *objs, **opts):
1697 '''Return the combined size of the given objects 1698 (with modified options, see also method set). 1699 ''' 1700 if opts: 1701 self.set(**opts) 1702 s, _ = self._sizes(objs, None) 1703 return s
1704
1705 - def asizesof(self, *objs, **opts):
1706 '''Return the individual sizes of the given objects 1707 (with modified options, see also method set). 1708 ''' 1709 if opts: 1710 self.set(**opts) 1711 _, t = self._sizes(objs, None) 1712 return t
1713
1714 - def exclude_refs(self, *objs):
1715 '''Exclude any references to the specified objects from sizing. 1716 1717 While any references to the given objects are excluded, the 1718 objects will be sized if specified as positional arguments 1719 in subsequent calls to methods asizeof and asizesof. 1720 ''' 1721 for o in objs: 1722 self._seen.setdefault(id(o), 0)
1723
1724 - def exclude_types(self, *objs):
1725 '''Exclude the specified object instances and types from sizing. 1726 1727 All instances and types of the given objects are excluded, 1728 even objects specified as positional arguments in subsequent 1729 calls to methods asizeof and asizesof. 1730 ''' 1731 for o in objs: 1732 for t in _keytuple(o): 1733 if t and t not in self._excl_d: 1734 self._excl_d[t] = 0
1735
1736 - def print_profiles(self, w=0, cutoff=0, **print3opts):
1737 '''Print the profiles above cutoff percentage. 1738 1739 w=0 -- indentation for each line 1740 cutoff=0 -- minimum percentage printed 1741 print3options -- print options, as in Python 3.0 1742 ''' 1743 # get the profiles with non-zero size or count 1744 t = [(v, k) for k, v in _items(self._profs) if v.total > 0 or v.number > 1] 1745 if (len(self._profs) - len(t)) < 9: # just show all 1746 t = [(v, k) for k, v in _items(self._profs)] 1747 if t: 1748 s = '' 1749 if self._total: 1750 s = ' (% of grand total)' 1751 c = max(cutoff, self._cutoff) 1752 c = int(c * 0.01 * self._total) 1753 else: 1754 c = 0 1755 _printf('%s%*d profile%s: total%s, average, and largest flat size%s: largest object', 1756 linesep, w, len(t), _plural(len(t)), s, self._incl, **print3opts) 1757 r = len(t) 1758 for v, k in _sorted(t, reverse=True): 1759 s = 'object%(plural)s: %(total)s, %(avg)s, %(high)s: %(obj)s%(lengstr)s' % v.format(self._clip_, self._total) 1760 _printf('%*d %s %s', w, v.number, self._prepr(k), s, **print3opts) 1761 r -= 1 1762 if r > 1 and v.total < c: 1763 c = max(cutoff, self._cutoff) 1764 _printf('%+*d profiles below cutoff (%.0f%%)', w, r, c) 1765 break 1766 z = len(self._profs) - len(t) 1767 if z > 0: 1768 _printf('%+*d %r object%s', w, z, 'zero', _plural(z), **print3opts)
1769
1770 - def print_stats(self, objs=(), opts={}, sized=(), sizes=(), stats=3.0, **print3opts):
1771 '''Print the statistics. 1772 1773 w=0 -- indentation for each line 1774 objs=() -- optional, list of objects 1775 opts={} -- optional, dict of options used 1776 sized=() -- optional, tuple of Asized instances returned 1777 sizes=() -- optional, tuple of sizes returned 1778 stats=3.0 -- print statistics and cutoff percentage 1779 print3options -- print options, as in Python 3.0 1780 ''' 1781 s = min(opts.get('stats', stats) or 0, self._stats_) 1782 if s > 0: # print stats 1783 t = self._total + self._missed + _sum(_values(self._seen)) 1784 w = len(str(t)) + 1 1785 t = c = '' 1786 o = _kwdstr(**opts) 1787 if o and objs: 1788 c = ', ' 1789 # print header line(s) 1790 if sized and objs: 1791 n = len(objs) 1792 if n > 1: 1793 _printf('%sasized(...%s%s) ...', linesep, c, o, **print3opts) 1794 for i in range(n): # no enumerate in Python 2.2.3 1795 _printf('%*d: %s', w-1, i, sized[i], **print3opts) 1796 else: 1797 _printf('%sasized(%s): %s', linesep, o, sized, **print3opts) 1798 elif sizes and objs: 1799 _printf('%sasizesof(...%s%s) ...', linesep, c, o, **print3opts) 1800 for z, o in zip(sizes, objs): 1801 _printf('%*d bytes%s%s: %s', w, z, _SI(z), self._incl, self._repr(o), **print3opts) 1802 else: 1803 if objs: 1804 t = self._repr(objs) 1805 _printf('%sasizeof(%s%s%s) ...', linesep, t, c, o, **print3opts) 1806 # print summary 1807 self.print_summary(w=w, objs=objs, **print3opts) 1808 if s > 1: # print profile 1809 c = int(s - int(s)) * 100 1810 self.print_profiles(w=w, cutoff=c, **print3opts) 1811 if s > 2: # print typedefs 1812 self.print_typedefs(w=w, **print3opts)
1813
1814 - def print_summary(self, w=0, objs=(), **print3opts):
1815 '''Print the summary statistics. 1816 1817 w=0 -- indentation for each line 1818 objs=() -- optional, list of objects 1819 print3options -- print options, as in Python 3.0 1820 ''' 1821 _printf('%*d bytes%s%s', w, self._total, _SI(self._total), self._incl, **print3opts) 1822 if self._mask: 1823 _printf('%*d byte aligned', w, self._mask + 1, **print3opts) 1824 _printf('%*d byte sizeof(void*)', w, _sizeof_Cvoidp, **print3opts) 1825 n = len(objs or ()) 1826 if n > 0: 1827 d = self._duplicate or '' 1828 if d: 1829 d = ', %d duplicate' % self._duplicate 1830 _printf('%*d object%s given%s', w, n, _plural(n), d, **print3opts) 1831 t = _sum([1 for t in _values(self._seen) if t != 0]) # [] for Python 2.2 1832 _printf('%*d object%s sized', w, t, _plural(t), **print3opts) 1833 if self._excl_d: 1834 t = _sum(_values(self._excl_d)) 1835 _printf('%*d object%s excluded', w, t, _plural(t), **print3opts) 1836 t = _sum(_values(self._seen)) 1837 _printf('%*d object%s seen', w, t, _plural(t), **print3opts) 1838 if self._missed > 0: 1839 _printf('%*d object%s missed', w, self._missed, _plural(self._missed), **print3opts) 1840 if self._depth > 0: 1841 _printf('%*d recursion depth', w, self._depth, **print3opts)
1842
1843 - def print_typedefs(self, w=0, **print3opts):
1844 '''Print the types and dict tables. 1845 1846 w=0 -- indentation for each line 1847 print3options -- print options, as in Python 3.0 1848 ''' 1849 for k in _all_kinds: 1850 # XXX Python 3.0 doesn't sort type objects 1851 t = [(self._prepr(a), v) for a, v in _items(_typedefs) if v.kind == k and (v.both or self._code_)] 1852 if t: 1853 _printf('%s%*d %s type%s: basicsize, itemsize, _len_(), _refs()', 1854 linesep, w, len(t), k, _plural(len(t)), **print3opts) 1855 for a, v in _sorted(t): 1856 _printf('%*s %s: %s', w, '', a, v, **print3opts) 1857 # dict and dict-like classes 1858 t = _sum([len(v) for v in _values(_dict_classes)]) # [] for Python 2.2 1859 if t: 1860 _printf('%s%*d dict/-like classes:', linesep, w, t, **print3opts) 1861 for m, v in _items(_dict_classes): 1862 _printf('%*s %s: %s', w, '', m, self._prepr(v), **print3opts)
1863
1864 - def set(self, align=None, code=None, detail=None, limit=None, stats=None):
1865 '''Set some options. Any options not set 1866 remain the same as the previous setting. 1867 1868 align=8 -- size alignment 1869 code=False -- incl. (byte)code size 1870 detail=0 -- Asized refs level 1871 limit=100 -- recursion limit 1872 stats=0.0 -- print statistics and cutoff percentage 1873 ''' 1874 # adjust 1875 if align is not None: 1876 self._align_ = align 1877 if align > 1: 1878 self._mask = align - 1 1879 if (self._mask & align) != 0: 1880 raise ValueError('invalid option: %s=%r' % ('align', align)) 1881 else: 1882 self._mask = 0 1883 if code is not None: 1884 self._code_ = code 1885 if code: # incl. (byte)code 1886 self._incl = ' (incl. code)' 1887 if detail is not None: 1888 self._detail_ = detail 1889 if limit is not None: 1890 self._limit_ = limit 1891 if stats is not None: 1892 self._stats_ = s = int(stats) 1893 self._cutoff = (stats - s) * 100 1894 if s > 1: # profile types 1895 self._profile = True 1896 else: 1897 self._profile = False
1898
1899 - def _get_duplicate(self):
1900 '''Number of duplicate objects. 1901 ''' 1902 return self._duplicate
1903 duplicate = property(_get_duplicate, doc=_get_duplicate.__doc__) 1904
1905 - def _get_missed(self):
1906 '''Number of objects missed due to errors. 1907 ''' 1908 return self._missed
1909 missed = property(_get_missed, doc=_get_missed.__doc__) 1910
1911 - def _get_total(self):
1912 '''Total size accumulated so far. 1913 ''' 1914 return self._total
1915 total = property(_get_total, doc=_get_total.__doc__) 1916
1917 - def reset(self, align=8, all=False, clip=80, code=False, derive=False, #PYCHOK expected 1918 detail=0, ignored=True, infer=False, limit=100, stats=0):
1919 '''Reset options, state, etc. 1920 1921 The available options and default values are: 1922 1923 align=8 -- size alignment 1924 all=False -- all current GC objects and referents 1925 clip=80 -- clip repr() strings 1926 code=False -- incl. (byte)code size 1927 derive=False -- derive from super type 1928 detail=0 -- Asized refs level 1929 ignored=True -- ignore certain types 1930 infer=False -- try to infer types 1931 limit=100 -- recursion limit 1932 stats=0.0 -- print statistics and cutoff percentage 1933 1934 See function asizeof for a description of the options. 1935 ''' 1936 # options 1937 self._align_ = align 1938 self._all_ = all 1939 self._clip_ = clip 1940 self._code_ = code 1941 self._derive_ = derive 1942 self._detail_ = detail # for Asized only 1943 self._infer_ = infer 1944 self._limit_ = limit 1945 self._stats_ = stats 1946 if ignored: 1947 self._ign_d = _kind_ignored 1948 else: 1949 self._ign_d = None 1950 # clear state 1951 self._clear() 1952 self.set(align=align, code=code, stats=stats)
1953 1954 1955 # public functions 1956
1957 -def adict(*classes):
1958 '''Install one or more classes to be handled as dict. 1959 ''' 1960 a = True 1961 for c in classes: 1962 # if class is dict-like, add class 1963 # name to _dict_classes[module] 1964 if isclass(c) and _infer_dict(c): 1965 t = _dict_classes.get(c.__module__, ()) 1966 if c.__name__ not in t: # extend tuple 1967 _dict_classes[c.__module__] = t + (c.__name__,) 1968 else: # not a dict-like class 1969 a = False 1970 return a # all installed if True
1971 1972 _asizer = Asizer() 1973
1974 -def asized(*objs, **opts):
1975 '''Return a tuple containing an Asized instance for each 1976 object passed as positional argment using the following 1977 options. 1978 1979 align=8 -- size alignment 1980 all=False -- all current GC objects and referents 1981 clip=80 -- clip repr() strings 1982 code=False -- incl. (byte)code size 1983 derive=False -- derive from super type 1984 detail=0 -- Asized refs level 1985 ignored=True -- ignore certain types 1986 infer=False -- try to infer types 1987 limit=100 -- recursion limit 1988 stats=0.0 -- print statistics and cutoff percentage 1989 1990 If only one object is given, the return value is the Asized 1991 instance for that object. 1992 1993 Set detail to the desired referents level (recursion depth). 1994 1995 See function asizeof for descriptions of the other options. 1996 1997 The length of the returned tuple matches the number of given 1998 objects, if more than one object is given. 1999 ''' 2000 t = _objs(objs, **opts) 2001 if t: 2002 _asizer.reset(**opts) 2003 s = _asizer.asized(*t) 2004 _asizer.print_stats(objs=t, opts=opts, sized=s) 2005 _asizer._clear() 2006 else: 2007 s = () 2008 return s
2009
2010 -def asizeof(*objs, **opts):
2011 '''Return the combined size in bytes of all objects passed 2012 as positional argments. 2013 2014 The available options and defaults are the following. 2015 2016 align=8 -- size alignment 2017 all=False -- all current GC objects and referents 2018 clip=80 -- clip ``repr()`` strings 2019 code=False -- incl. (byte)code size 2020 derive=False -- derive from super type 2021 ignored=True -- ignore certain types 2022 infer=False -- try to infer types 2023 limit=100 -- recursion limit 2024 stats=0.0 -- print statistics and cutoff percentage 2025 2026 Set align to a power of 2 to align sizes. Any value less 2027 than 2 avoids size alignment. 2028 2029 All current GC objects are sized if all is True and if no 2030 positional arguments are supplied. Also, if all is True 2031 the GC referents are used instead of the limited ones. 2032 2033 A positive clip value truncates all repr() strings to at 2034 most clip characters. 2035 2036 The (byte)code size of callable objects like functions, 2037 methods, classes, etc. is included only if code is True. 2038 2039 If derive is True, new types are handled like an existing 2040 (super) type provided there is one and only of those. 2041 2042 By default, certain base types like object are ignored for 2043 sizing. Set ignored to False to force all ignored types 2044 in the size of objects. 2045 2046 By default certain base types like object, super, etc. are 2047 ignored. Set ignored to False to include those. 2048 2049 If infer is True, new types are inferred from attributes 2050 (only implemented for dict types on callable attributes 2051 as get, has_key, items, keys and values). 2052 2053 Set limit to a positive value to accumulate the sizes of 2054 the referents of each object, recursively up to the limit. 2055 Using limit zero returns the sum of the flat [1] sizes of 2056 the given objects. High limit values may cause runtime 2057 errors and miss objects for sizing. 2058 2059 A positive value for stats prints up to 8 statistics, (1) 2060 a summary of the number of objects sized and seen, (2) a 2061 simple profile of the sized objects by type and (3+) up to 2062 6 tables showing the static, dynamic, derived, ignored, 2063 inferred and dict types used, found respectively installed. 2064 2065 The fractional part of the stats value (x 100) is the cutoff 2066 percentage for simple profiles. Objects below the cutoff 2067 value are not reported. 2068 2069 [1] See the documentation of this module for the definition 2070 of flat size. 2071 ''' 2072 t = _objs(objs, **opts) 2073 if t: 2074 _asizer.reset(**opts) 2075 s = _asizer.asizeof(*t) 2076 _asizer.print_stats(objs=t, opts=opts) 2077 _asizer._clear() 2078 else: 2079 s = 0 2080 return s
2081
2082 -def asizesof(*objs, **opts):
2083 '''Return a tuple containing the size in bytes of all objects 2084 passed as positional argments using the following options. 2085 2086 align=8 -- size alignment 2087 all=False -- use GC objects and referents 2088 clip=80 -- clip ``repr()`` strings 2089 code=False -- incl. (byte)code size 2090 derive=False -- derive from super type 2091 ignored=True -- ignore certain types 2092 infer=False -- try to infer types 2093 limit=100 -- recursion limit 2094 stats=0.0 -- print statistics and cutoff percentage 2095 2096 See function asizeof for a description of the options. 2097 2098 The length of the returned tuple equals the number of given 2099 objects. 2100 ''' 2101 t = _objs(objs, **opts) 2102 if t: 2103 _asizer.reset(**opts) 2104 s = _asizer.asizesof(*t) 2105 _asizer.print_stats(objs=t, opts=opts, sizes=s) 2106 _asizer._clear() 2107 else: 2108 s = () 2109 return s
2110
2111 -def _typedefof(obj, save=False, **opts):
2112 '''Get the typedef for an object. 2113 ''' 2114 k = _objkey(obj) 2115 v = _typedefs.get(k, None) 2116 if not v: # new typedef 2117 v = _typedef(obj, **opts) 2118 if save: 2119 _typedefs[k] = v 2120 return v
2121
2122 -def basicsize(obj, **opts):
2123 '''Return the basic size of an object (in bytes). 2124 2125 Valid options and defaults are 2126 derive=False -- derive type from super type 2127 infer=False -- try to infer types 2128 save=False -- save typedef if new 2129 ''' 2130 v = _typedefof(obj, **opts) 2131 if v: 2132 v = v.base 2133 return v
2134
2135 -def flatsize(obj, align=0, **opts):
2136 '''Return the flat size of an object (in bytes), 2137 optionally aligned to a given power of 2. 2138 2139 See function basicsize for a description of 2140 the other options. See the documentation of 2141 this module for the definition of flat size. 2142 ''' 2143 v = _typedefof(obj, **opts) 2144 if v: 2145 if align > 1: 2146 m = align - 1 2147 if (align & m) != 0: 2148 raise ValueError('invalid option: %s=%r' % ('align', align)) 2149 else: 2150 m = 0 2151 v = v.flat(obj, m) 2152 return v
2153
2154 -def itemsize(obj, **opts):
2155 '''Return the item size of an object (in bytes). 2156 2157 See function basicsize for a description of 2158 the options. 2159 ''' 2160 v = _typedefof(obj, **opts) 2161 if v: 2162 v = v.item 2163 return v
2164
2165 -def leng(obj, **opts):
2166 '''Return the length of an object (in items). 2167 2168 See function basicsize for a description 2169 of the options. 2170 ''' 2171 v = _typedefof(obj, **opts) 2172 if v: 2173 v = v.leng 2174 if v and _callable(v): 2175 v = v(obj) 2176 return v
2177
2178 -def refs(obj, all=False, **opts):
2179 '''Return (a generator for) specific referents of an 2180 object. 2181 2182 If all is True return the GC referents. 2183 2184 See function basicsize for a description of the 2185 options. 2186 ''' 2187 v = _typedefof(obj, **opts) 2188 if v: 2189 if all: # == True 2190 v = _getreferents(obj) 2191 else: 2192 v = v.refs 2193 if v and _callable(v): 2194 v = v(obj, False) 2195 return v
2196 2197 2198 if __name__ == '__main__': 2199 2200 argv, MAX = sys.argv, sys.getrecursionlimit() 2201
2202 - def _print_asizeof(obj, infer=False, stats=0):
2203 a = [_repr(obj),] 2204 for d, c in ((0, False), (MAX, False), (MAX, True)): 2205 a.append(asizeof(obj, limit=d, code=c, infer=infer, stats=stats)) 2206 _printf(" asizeof(%s) is %d, %d, %d", *a)
2207
2208 - def _print_functions(obj, name=None, align=8, detail=MAX, code=False, limit=MAX, 2209 opt='', **unused):
2210 if name: 2211 _printf('%sasizeof functions for %s ... %s', linesep, name, opt) 2212 _printf('%s(): %s', ' basicsize', basicsize(obj)) 2213 _printf('%s(): %s', ' itemsize', itemsize(obj)) 2214 _printf('%s(): %r', ' leng', leng(obj)) 2215 _printf('%s(): %s', ' refs', _repr(refs(obj))) 2216 _printf('%s(): %s', ' flatsize', flatsize(obj, align=align)) # , code=code 2217 _printf('%s(): %s', ' asized', asized(obj, align=align, detail=detail, code=code, limit=limit))
2218 ##_printf('%s(): %s', '.asized', _asizer.asized(obj, align=align, detail=detail, code=code, limit=limit)) 2219
2220 - def _bool(arg):
2221 a = arg.lower() 2222 if a in ('1', 't', 'y', 'true', 'yes', 'on'): 2223 return True 2224 elif a in ('0', 'f', 'n', 'false', 'no', 'off'): 2225 return False 2226 else: 2227 raise ValueError('bool option expected: %r' % arg)
2228
2229 - def _opts(*opts):
2230 '''Return True if any oof the given options 2231 was present in the command line arguments. 2232 ''' 2233 for o in opts + ('-', '--'): 2234 if o in argv: 2235 return True 2236 return False
2237 2238 if '-im' in argv or '-import' in argv: 2239 # import and size modules given as args 2240
2241 - def _aopts(argv, **opts):
2242 '''Get argv options as typed values. 2243 ''' 2244 i = 1 2245 while argv[i].startswith('-'): 2246 k = argv[i].lstrip('-') 2247 if 'import'.startswith(k): 2248 i += 1 2249 elif k in opts: 2250 t = type(opts[k]) 2251 if t is bool: 2252 t = _bool 2253 i += 1 2254 opts[k] = t(argv[i]) 2255 i += 1 2256 else: 2257 raise NameError('invalid option: %s' % argv[i]) 2258 return opts, i
2259 2260 opts, i = _aopts(argv, align=8, clip=80, code=False, derive=False, detail=MAX, limit=MAX, stats=0) 2261 while i < len(argv): 2262 m, i = argv[i], i + 1 2263 if m == 'eval' and i < len(argv): 2264 o, i = eval(argv[i]), i + 1 2265 else: 2266 o = __import__(m) 2267 s = asizeof(o, **opts) 2268 _printf("%sasizeof(%s) is %d", linesep, _repr(o, opts['clip']), s) 2269 _print_functions(o, **opts) 2270 argv = [] 2271 2272 elif len(argv) < 2 or _opts('-h', '-help'): 2273 d = {'-all': 'all=True example', 2274 '-basic': 'basic examples', 2275 '-C': 'Csizeof values', 2276 '-class': 'class and instance examples', 2277 '-code': 'code examples', 2278 '-dict': 'dict and UserDict examples', 2279 ##'-gc': 'gc examples', 2280 '-gen[erator]': 'generator examples', 2281 '-glob[als]': 'globals examples, incl. asized()', 2282 '-h[elp]': 'print this information', 2283 '-im[port] <module>': 'imported module example', 2284 '-int | -long': 'int and long examples', 2285 '-iter[ator]': 'iterator examples', 2286 '-loc[als]': 'locals examples', 2287 '-pair[s]': 'key pair examples', 2288 '-slots': 'slots examples', 2289 '-stack': 'stack examples', 2290 '-sys': 'sys.modules examples', 2291 '-test': 'test flatsize() vs sys.getsizeof()', 2292 '-type[def]s': 'type definitions', 2293 '- | --': 'all examples'} 2294 w = -max([len(o) for o in _keys(d)]) # [] for Python 2.2 2295 t = _sorted(['%*s -- %s' % (w, o, t) for o, t in _items(d)]) # [] for Python 2.2 2296 t = '\n '.join([''] + t) 2297 _printf('usage: %s <option> ...\n%s\n', argv[0], t) 2298
2299 - class C: pass
2300
2301 - class D(dict):
2302 _attr1 = None 2303 _attr2 = None
2304
2305 - class E(D):
2306 - def __init__(self, a1=1, a2=2): #PYCHOK OK
2307 self._attr1 = a1 #PYCHOK OK 2308 self._attr2 = a2 #PYCHOK OK
2309
2310 - class P(object):
2311 _p = None
2312 - def _get_p(self):
2313 return self._p
2314 p = property(_get_p) #PYCHOK OK
2315
2316 - class O: # old style
2317 a = None 2318 b = None 2319
2320 - class S(object): # new style
2321 __slots__ = ('a', 'b') 2322
2323 - class T(object):
2324 __slots__ = ('a', 'b')
2325 - def __init__(self):
2326 self.a = self.b = 0
2327 2328 if _opts('-all'): # all=True example 2329 _printf('%sasizeof(limit=%s, code=%s, %s) ... %s', linesep, 'MAX', True, 'all=True', '-all') 2330 asizeof(limit=MAX, code=True, stats=MAX, all=True) 2331 2332 if _opts('-basic'): # basic examples 2333 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<basic_objects>', '((0, False), (MAX, False), (MAX, True))', '-basic') 2334 for o in (None, True, False, 2335 1.0, 1.0e100, 1024, 1000000000, 2336 '', 'a', 'abcdefg', 2337 {}, (), []): 2338 _print_asizeof(o, infer=True) 2339 2340 if _opts('-C'): # show all Csizeof values 2341 _sizeof_Cdouble = calcsize('d') #PYCHOK OK 2342 _sizeof_Csize_t = calcsize('Z') #PYCHOK OK 2343 _sizeof_Cssize_t = calcsize('z') #PYCHOK OK 2344 t = [t for t in locals().items() if t[0].startswith('_sizeof_')] 2345 _printf('%s%d C sizes: (bytes) ... -C', linesep, len(t)) 2346 for n, v in _sorted(t): 2347 _printf(' sizeof(%s): %r', n[len('_sizeof_'):], v) 2348 2349 if _opts('-class'): # class and instance examples 2350 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<non-callable>', '((0, False), (MAX, False), (MAX, True))', '-class') 2351 for o in (C(), C.__dict__, 2352 D(), D.__dict__, 2353 E(), E.__dict__, 2354 P(), P.__dict__, P.p, 2355 O(), O.__dict__, 2356 S(), S.__dict__, 2357 S(), S.__dict__, 2358 T(), T.__dict__): 2359 _print_asizeof(o, infer=True) 2360 2361 if _opts('-code'): # code examples 2362 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<callable>', '((0, False), (MAX, False), (MAX, True))', '-code') 2363 for o in (C, D, E, P, S, T, # classes are callable 2364 type, 2365 _co_refs, _dict_refs, _inst_refs, _len_int, _seq_refs, lambda x: x, 2366 (_co_refs, _dict_refs, _inst_refs, _len_int, _seq_refs), 2367 _typedefs): 2368 _print_asizeof(o) 2369 2370 if _opts('-dict'): # dict and UserDict examples 2371 _printf('%sasizeof(%s) for (limit, code) in %s ... %s', linesep, '<Dicts>', '((0, False), (MAX, False), (MAX, True))', '-dict') 2372 try: 2373 import UserDict # no UserDict in 3.0 2374 for o in (UserDict.IterableUserDict(), UserDict.UserDict()): 2375 _print_asizeof(o) 2376 except ImportError: 2377 pass 2378
2379 - class _Dict(dict):
2380 pass
2381 2382 for o in (dict(), _Dict(), 2383 P.__dict__, # dictproxy 2384 Weakref.WeakKeyDictionary(), Weakref.WeakValueDictionary(), 2385 _typedefs): 2386 _print_asizeof(o, infer=True) 2387 2388 ##if _opts('-gc'): # gc examples 2389 ##_printf('%sasizeof(limit=%s, code=%s, *%s) ...', linesep, 'MAX', False, 'gc.garbage') 2390 ##from gc import collect, garbage # list() 2391 ##asizeof(limit=MAX, code=False, stats=1, *garbage) 2392 ##collect() 2393 ##asizeof(limit=MAX, code=False, stats=2, *garbage) 2394 2395 if _opts('-gen', '-generator'): # generator examples 2396 _printf('%sasizeof(%s, code=%s) ... %s', linesep, '<generator>', True, '-gen[erator]')
2397 - def gen(x):
2398 i = 0 2399 while i < x: 2400 yield i 2401 i += 1
2402 a = gen(5) 2403 b = gen(50) 2404 asizeof(a, code=True, stats=1) 2405 asizeof(b, code=True, stats=1) 2406 asizeof(a, code=True, stats=1) 2407 2408 if _opts('-glob', '-globals'): # globals examples 2409 _printf('%sasizeof(%s, limit=%s, code=%s) ... %s', linesep, 'globals()', 'MAX', False, '-glob[als]') 2410 asizeof(globals(), limit=MAX, code=False, stats=1) 2411 _print_functions(globals(), 'globals()', opt='-glob[als]') 2412 2413 _printf('%sasizesof(%s, limit=%s, code=%s) ... %s', linesep, 'globals(), locals()', 'MAX', False, '-glob[als]') 2414 asizesof(globals(), locals(), limit=MAX, code=False, stats=1) 2415 asized(globals(), align=0, detail=MAX, limit=MAX, code=False, stats=1) 2416 2417 if _opts('-int', '-long'): # int and long examples 2418 try: 2419 _L5d = long(1) << 64 2420 _L17d = long(1) << 256 2421 t = '<int>/<long>' 2422 except NameError: 2423 _L5d = 1 << 64 2424 _L17d = 1 << 256 2425 t = '<int>' 2426 2427 _printf('%sasizeof(%s, align=%s, limit=%s) ... %s', linesep, t, 0, 0, '-int') 2428 for o in (1024, 1000000000, 2429 1.0, 1.0e100, 1024, 1000000000, 2430 MAX, 1 << 32, _L5d, -_L5d, _L17d, -_L17d): 2431 _printf(" asizeof(%s) is %s (%s + %s * %s)", _repr(o), asizeof(o, align=0, limit=0), 2432 basicsize(o), leng(o), itemsize(o)) 2433 2434 if _opts('-iter', '-iterator'): # iterator examples 2435 _printf('%sasizeof(%s, code=%s) ... %s', linesep, '<iterator>', False, '-iter[ator]') 2436 o = iter('0123456789') 2437 e = iter('') 2438 d = iter({}) 2439 i = iter(_items({1:1})) 2440 k = iter(_keys({2:2, 3:3})) 2441 v = iter(_values({4:4, 5:5, 6:6})) 2442 l = iter([]) 2443 t = iter(()) 2444 asizesof(o, e, d, i, k, v, l, t, limit=0, code=False, stats=1) 2445 asizesof(o, e, d, i, k, v, l, t, limit=9, code=False, stats=1) 2446 2447 if _opts('-loc', '-locals'): # locals examples 2448 _printf('%sasizeof(%s, limit=%s, code=%s) ... %s', linesep, 'locals()', 'MAX', False, '-loc[als]') 2449 asizeof(locals(), limit=MAX, code=False, stats=1) 2450 _print_functions(locals(), 'locals()', opt='-loc[als]') 2451 2452 if _opts('-pair', '-pairs'): # key pair examples 2453 # <http://jjinux.blogspot.com/2008/08/python-memory-conservation-tip.html> 2454 _printf('%sasizeof(%s) vs asizeof(%s) ... %s', linesep, 'dict[i][j]', 'dict[(i,j)]', '-pair[s]') 2455 n = m = 200 2456 2457 p = {} # [i][j] 2458 for i in range(n): 2459 q = {} 2460 for j in range(m): 2461 q[j] = None 2462 p[i] = q 2463 p = asizeof(p, stats=1) 2464 2465 t = {} # [(i,j)] 2466 for i in range(n): 2467 for j in range(m): 2468 t[(i,j)] = None 2469 t = asizeof(t, stats=1) 2470 2471 _printf('%sasizeof(dict[i][j]) is %s of asizeof(dict[(i,j)])', linesep, _p100(p, t)) 2472 2473 if _opts('-slots'): # slots examples 2474 _printf('%sasizeof(%s, code=%s) ... %s', linesep, '<__slots__>', False, '-slots')
2475 - class Old:
2476 pass # m = None
2477 - class New(object):
2478 __slots__ = ('n',)
2479 - class Sub(New): #PYCHOK OK
2480 __slots__ = {'s': ''} # duplicate!
2481 - def __init__(self): #PYCHOK OK
2482 New.__init__(self) 2483 # basic instance sizes 2484 o, n, s = Old(), New(), Sub() 2485 asizesof(o, n, s, limit=MAX, code=False, stats=1) 2486 # with unique min attr size 2487 o.o = 'o' 2488 n.n = 'n' 2489 s.n = 'S' 2490 s.s = 's' 2491 asizesof(o, n, s, limit=MAX, code=False, stats=1) 2492 # with duplicate, intern'ed, 1-char string attrs 2493 o.o = 'x' 2494 n.n = 'x' 2495 s.n = 'x' 2496 s.s = 'x' 2497 asizesof(o, n, s, 'x', limit=MAX, code=False, stats=1) 2498 # with larger attr size 2499 o.o = 'o'*1000 2500 n.n = 'n'*1000 2501 s.n = 'n'*1000 2502 s.s = 's'*1000 2503 asizesof(o, n, s, 'x'*1000, limit=MAX, code=False, stats=1) 2504 2505 if _opts('-stack'): # stack examples 2506 _printf('%sasizeof(%s, limit=%s, code=%s) ... %s', linesep, 'stack(MAX)', 'MAX', False, '') 2507 asizeof(stack(MAX), limit=MAX, code=False, stats=1) 2508 _print_functions(stack(MAX), 'stack(MAX)', opt='-stack') 2509 2510 if _opts('-sys'): # sys.modules examples 2511 _printf('%sasizeof(limit=%s, code=%s, *%s) ... %s', linesep, 'MAX', False, 'sys.modules.values()', '-sys') 2512 asizeof(limit=MAX, code=False, stats=1, *sys.modules.values()) 2513 _print_functions(sys.modules, 'sys.modules', opt='-sys') 2514 2515 if _opts('-type', '-types', '-typedefs'): # show all basic _typedefs 2516 t = len(_typedefs) 2517 w = len(str(t)) * ' ' 2518 _printf('%s%d type definitions: basic- and itemsize (leng), kind ... %s', linesep, t, '-type[def]s') 2519 for k, v in _sorted([(_prepr(k), v) for k, v in _items(_typedefs)]): # [] for Python 2.2 2520 s = '%(base)s and %(item)s%(leng)s, %(kind)s%(code)s' % v.format() 2521 _printf('%s %s: %s', w, k, s) 2522 2523 if _opts('-test'): 2524 # compare the results of flatsize() *without* using sys.getsizeof() 2525 # with the accurate sizes returned by sys.getsizeof() but expect 2526 # differences for sequences as dicts, lists, sets, tuples, etc. 2527 # while this is no proof for the accuracy of flatsize() on Python 2528 # builds without sys.getsizeof(), it does provide some evidence 2529 # that that flatsize() produces reasonable and usable results 2530 _printf('%sflatsize() vs sys.getsizeof() ... %s', linesep, '-test') 2531 t, g, e = [], _getsizeof, 0 2532 if g: 2533 for v in _values(_typedefs): 2534 t.append(v.type) 2535 try: # creating one instance 2536 if v.type.__module__ not in ('io',): # avoid 3.0 RuntimeWarning 2537 t.append(v.type()) 2538 except (AttributeError, SystemError, TypeError, ValueError): # ignore errors 2539 pass 2540 t.extend(({1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}, 2541 [1,2,3,4,5,6,7,8], ['1', '2', '3'], [0] * 100, 2542 '12345678', 'x' * 1001, 2543 (1,2,3,4,5,6,7,8), ('1', '2', '3'), (0,) * 100, 2544 _Slots((1,2,3,4,5,6,7,8)), _Slots(('1', '2', '3')), _Slots((0,) * 100), 2545 0, 1 << 8, 1 << 16, 1 << 32, 1 << 64, 1 << 128, 2546 complex(0, 1), True, False)) 2547 _getsizeof = None # zap _getsizeof for flatsize() 2548 for o in t: 2549 a = flatsize(o) 2550 s = sys.getsizeof(o, 0) # 0 as default #PYCHOK expected 2551 if a != s: 2552 # flatsize approximates the length of sequences 2553 # (sys.getsizeof(bool) on 3.0b3 is not correct) 2554 if type(o) in (dict, list, set, frozenset, tuple) or ( 2555 type(o) in (bool,) and sys.version_info[0] == 3): 2556 x = 'expected failure' 2557 else: 2558 x = '%r' % _typedefof(o) 2559 e += 1 2560 _printf('flatsize() %s vs sys.getsizeof() %s for %s: %s, %s', 2561 a, s, _nameof(type(o)), _repr(o), x) 2562 _getsizeof = g # restore 2563 n, p = len(t), 'python %s' % sys.version.split()[0] 2564 if e: 2565 _printf('%s%d of %d tests failed or %s on %s', linesep, e, n, _p100(e, n), p) 2566 elif g: 2567 _printf('no unexpected failures in %d tests on %s', n, p) 2568 else: 2569 _printf('no sys.%s() in this %s', 'getsizeof', p) 2570 2571 2572 # License file from an earlier version of this source file follows: 2573 2574 #--------------------------------------------------------------------- 2575 # Copyright (c) 2002-2009 -- ProphICy Semiconductor, Inc. 2576 # All rights reserved. 2577 # 2578 # Redistribution and use in source and binary forms, with or without 2579 # modification, are permitted provided that the following conditions 2580 # are met: 2581 # 2582 # - Redistributions of source code must retain the above copyright 2583 # notice, this list of conditions and the following disclaimer. 2584 # 2585 # - Redistributions in binary form must reproduce the above copyright 2586 # notice, this list of conditions and the following disclaimer in 2587 # the documentation and/or other materials provided with the 2588 # distribution. 2589 # 2590 # - Neither the name of ProphICy Semiconductor, Inc. nor the names 2591 # of its contributors may be used to endorse or promote products 2592 # derived from this software without specific prior written 2593 # permission. 2594 # 2595 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2596 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2597 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2598 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2599 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2600 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2601 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2602 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2603 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2604 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2605 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 2606 # OF THE POSSIBILITY OF SUCH DAMAGE. 2607 #--------------------------------------------------------------------- 2608