modified: src1/input.c
[GalaxyCodeBases.git] / python / Gsite / Galaxy / asizeof.py
blob30f0bfff22ec31e50bd4876e947a65c1e2caff7b
1 #!/usr/bin/env python
3 # Copyright, license and disclaimer are at the very end of this file.
5 # This is the latest, enhanced version of the asizeof.py recipes at
6 # <http://github.com/ActiveState/code/blob/master/recipes/Python/
7 # 546530_Size_of_Python_objects_revised/recipe-546530.py>,
8 # <http://code.activestate.com/recipes/546530-size-of-python-objects-revised>
9 # and <http://code.activestate.com/recipes/544288-size-of-python-objects>.
11 # Recent versions of this module handle objects like ``namedtuples``,
12 # ``closure``, and NumPy data ``arange``, ``array``, ``matrix``, etc.
14 # See also project Pympler at <https://github.com/pympler/pympler> and
15 # memory footprint recipe <http://code.activestate.com/recipes/577504/>.
17 # Tested with 64-bit Python 2.6.9 (and numpy 1.6.2), 2.7.13 (and numpy
18 # 1.13.1), 3.5.3 and 3.6.2 on macOS 10.12.6 Sierra, with 64-bit Intel-
19 # Python 3.5.3 (and numpy 1.11.3) on macOS 10.12.6 Sierra and with
20 # Pythonista 3.1 using 64-bit Python 2.7.12 and 3.5.1 (both with numpy
21 # 1.8.0) on iOS 10.3.3.
23 # Earlier versions of this module were tested with 32-bit Python 2.2.3,
24 # 2.3.7, 2.4.5, 2.5.1, 2.5.2, 2.6.2, 3.0.1 or 3.1a2 on CentOS 4.6, SuSE
25 # 9.3, MacOS X 10.3.9 Panther (PPC), MacOS X 10.4.11 Tiger, Solaris 10
26 # (Opteron) and Windows XP, with 64-bit Python 3.0.1 on RHEL 3u7 and
27 # Solaris 10 (Opteron) and with 64-bit Python 2.7.10 and 3.5.1 on MacOS
28 # X 10.11.5 El Capitan (all without numpy).
30 # This module was checked statically with PyChecker 0.8.12, PyFlakes
31 # 1.5.0, PyCodeStyle 2.3.1 (formerly Pep8) and McCabe 0.6.1 using Python
32 # 2.7.13 and with Flake8 3.3.0 using Python 3.6.2, all thru this post-
33 # processor <http://code.activestate.com/recipes/546532/>
35 '''
36 This module exposes 9 functions and 2 classes to obtain lengths (in
37 items) and sizes (in bytes) of Python objects for Python 2.6 and later,
38 including Python 3+ [#v]_.
40 **Public Functions** [#unsafe]_
42 Function **asizeof** calculates the combined (approximate) size
43 in bytes of one or several Python objects.
45 Function **asizesof** returns a tuple containing the (approximate)
46 size in bytes for each given Python object separately.
48 Function **asized** returns for each object an instance of class
49 **Asized** containing all the size information of the object and
50 a tuple with the referents [#refs]_.
52 Functions **basicsize** and **itemsize** return the *basic*
53 respectively *itesize* of the given object, both in bytes. For
54 objects as ``array.array``, ``numpy.array``, ``numpy.matrix``,
55 etc. where the item size varies depending on the instance-specific
56 data type, function **itemsize** returns that item size.
58 Function **flatsize** returns the *flat size* of a Python object
59 in bytes defined as the *basic size* plus the *item size* times
60 the *length* of the given object.
62 Function **alen** [#alen]_ returns the *length* of an object like
63 standard function ``len`` but extended for several types. E.g.
64 the **alen** of a multi-precision int (or long) is the number of
65 ``digits`` [#digit]_. The *length* of most *mutable* sequence
66 objects includes an estimate of the over-allocation and therefore,
67 the **alen** value may differ from the standard ``len`` result.
68 For objects like ``array.array``, ``numpy.array``, ``numpy.matrix``,
69 etc. function **alen** returns the proper number of items.
71 Function **refs** returns (a generator for) the referents [#refs]_
72 of the given object.
74 Certain classes are known to be sub-classes of or to behave as
75 ``dict`` objects. Function **adict** can be used to install
76 other class objects to be treated like ``dict``.
78 **Public Classes** [#unsafe]_
80 Class **Asizer** may be used to accumulate the results of several
81 sizing calls. After creating an **Asizer** instance, use methods
82 **asizeof** and **asizesof** as needed to size any number of
83 additional objects and accumulate the sizes.
85 Call methods **exclude_refs** and/or **exclude_types** to exclude
86 references to respectively instances or types of certain objects.
88 Use one of the **print\_...** methods to report the statistics.
90 An instance of class **Asized** is returned for each object sized
91 with the **asized** function or method.
93 **Duplicate Objects**
95 Any duplicate, given objects are sized only once and the size
96 is included in the combined total only once. But functions
97 **asizesof** and **asized** will return a size value respectively
98 an **Asized** instance for each given object, including duplicates.
100 **Definitions** [#arb]_
102 The *length* of an objects like ``dict``, ``list``, ``set``,
103 ``str``, ``tuple``, etc. is defined as the number of items held
104 in or allocated by the object. Held items are *references* to
105 other objects, called the *referents*.
107 The *size* of an object is defined as the sum of the *flat size*
108 of the object plus the sizes of any referents [#refs]_. Referents
109 are visited recursively up to the specified detail level. However,
110 the size of objects referenced multiple times is included only once
111 in the total *size*.
113 The *flat size* of an object is defined as the *basic size* of the
114 object plus the *item size* times the number of allocated *items*,
115 *references* to referents. The *flat size* does include the size
116 for the *references* to the referents, but not the size of the
117 referents themselves.
119 The *flat size* returned by function *flatsize* equals the result
120 of function *asizeof* with options *code=True*, *ignored=False*,
121 *limit=0* and option *align* set to the same value.
123 The accurate *flat size* for an object is obtained from function
124 ``sys.getsizeof()`` where available. Otherwise, the *length* and
125 *size* of sequence objects as ``dicts``, ``lists``, ``sets``, etc.
126 is based on an estimate for the number of allocated items. As a
127 result, the reported *length* and *size* may differ substantially
128 from the actual *length* and *size*.
130 The *basic* and *item size* are obtained from the ``__basicsize__``
131 respectively ``__itemsize__`` attributes of the (type of the)
132 object. Where necessary (e.g. sequence objects), a zero
133 ``__itemsize__`` is replaced by the size of a corresponding C type.
135 The overhead for Python's garbage collector (GC) is included in
136 the *basic size* of (GC managed) objects as well as the space
137 needed for ``refcounts`` (used only in certain Python builds).
139 Optionally, size values can be aligned to any power of 2 multiple.
141 **Size of (byte)code**
143 The *(byte)code size* of objects like classes, functions, methods,
144 modules, etc. can be included by setting option *code=True*.
146 Iterators are handled like sequences: iterated object(s) are
147 sized like *referents* [#refs]_ but only up to the specified level
148 or recursion *limit* (and only if function ``gc.get_referents()``
149 returns the referent object of iterators).
151 Generators are sized as *(byte)code* only, but the generated objects
152 are never sized.
154 **Old- and New-style Classes**
156 All old- and new-style ``class``, instance and ``type`` objects,
157 are handled uniformly such that (a) instance objects are distinguished
158 from class objects and (b) instances of different old-style classes
159 can be dealt with separately.
161 Class and type objects are represented as ``<class ....* def>``
162 respectively ``<type ... def>`` where the ``*`` indicates an old-style
163 class and the ``... def`` suffix marks the *definition object*.
164 Instances of classes are shown as ``<class module.name*>`` without
165 the ``... def`` suffix. The ``*`` after the name indicates an
166 instance of an old-style class.
168 **Ignored Objects**
170 To avoid excessive sizes, several object types are ignored [#arb]_
171 by default, e.g. built-in functions, built-in types and classes
172 [#bi]_, function globals and module referents. However, any
173 instances thereof and module objects will be sized when passed as
174 given objects. Ignored object types are included unless option
175 *ignored* is set accordingly.
177 In addition, many ``__...__`` attributes of callable objects are
178 ignored [#arb]_, except crucial ones, e.g. class attributes ``__dict__``,
179 ``__doc__``, ``__name__`` and ``__slots__``. For more details, see
180 the type-specific ``_..._refs()`` and ``_len_...()`` functions below.
182 .. rubric:: Footnotes
183 .. [#unsafe] The functions and classes in this module are not thread-safe.
185 .. [#v] Earlier editions of this module supported Python versions down
186 to Python 2.2. To use Python 2.5 or older, try module ``asizeof``
187 from project `Pympler 0.3.x <https://github.com/pympler/pympler>`_.
189 .. [#alen] Former function *leng*, class attribute *leng* and keyword
190 argument *leng* have all been renamed to *alen*. However, function
191 *leng* is still available for backward compatibility.
193 .. [#refs] The *referents* of an object are the objects referenced *by*
194 that object. For example, the *referents* of a ``list`` are the
195 objects held in the ``list``, the *referents* of a ``dict`` are
196 the key and value objects in the ``dict``, etc.
198 .. [#arb] These definitions and other assumptions are rather arbitrary
199 and may need corrections or adjustments.
201 .. [#digit] See Python source file ``.../Include/longinterp.h`` for the
202 C ``typedef`` of ``digit`` used in multi-precision int (or long)
203 objects. The C ``sizeof(digit)`` in bytes can be obtained in
204 Python from the int (or long) ``__itemsize__`` attribute.
205 Function **alen** determines the number of ``digits`` of an int
206 (or long) object.
208 .. [#bi] ``Type``s and ``class``es are considered built-in if the
209 ``__module__`` of the type or class is listed in the private
210 ``_builtin_modules``.
212 import sys
213 if sys.version_info < (2, 6, 0):
214 raise NotImplementedError('%s requires Python 2.6 or newer' % ('asizeof',))
216 from inspect import (isbuiltin, isclass, iscode, isframe, isfunction,
217 ismethod, ismodule, stack)
218 from math import log
219 from os import curdir, linesep
220 from struct import calcsize # type/class Struct only in Python 2.5+
221 import types as Types
222 import warnings
223 import weakref as Weakref
225 __all__ = ['adict', 'asized', 'asizeof', 'asizesof',
226 'Asized', 'Asizer', # classes
227 'basicsize', 'flatsize', 'itemsize', 'alen', 'refs']
228 __version__ = '17.08.24'
230 # any classes or types in modules listed in _builtin_modules are
231 # considered built-in and ignored by default, as built-in functions
232 if __name__ == '__main__':
233 _builtin_modules = (int.__module__, 'types', Exception.__module__) # , 'weakref'
234 else: # treat this very module as built-in
235 _builtin_modules = (int.__module__, 'types', Exception.__module__, __name__) # , 'weakref'
237 # sizes of some primitive C types
238 # XXX len(pack(T, 0)) == Struct(T).size == calcsize(T)
239 _sizeof_Cbyte = calcsize('c') # sizeof(unsigned char)
240 _sizeof_Clong = calcsize('l') # sizeof(long)
241 _sizeof_Cvoidp = calcsize('P') # sizeof(void*)
243 # sizeof(long) != sizeof(ssize_t) on LLP64
244 if _sizeof_Clong < _sizeof_Cvoidp: # pragma: no coverage
245 _z_P_L = 'P'
246 else:
247 _z_P_L = 'L'
250 def _calcsize(fmt):
251 '''Like struct.calcsize() but handling 'z' for Py_ssize_t.
253 return calcsize(fmt.replace('z', _z_P_L))
256 # defaults for some basic sizes with 'z' for C Py_ssize_t
257 _sizeof_CPyCodeObject = _calcsize('Pz10P5i0P') # sizeof(PyCodeObject)
258 _sizeof_CPyFrameObject = _calcsize('Pzz13P63i0P') # sizeof(PyFrameObject)
259 _sizeof_CPyModuleObject = _calcsize('PzP0P') # sizeof(PyModuleObject)
261 # defaults for some item sizes with 'z' for C Py_ssize_t
262 _sizeof_CPyDictEntry = _calcsize('z2P') # sizeof(PyDictEntry)
263 _sizeof_Csetentry = _calcsize('lP') # sizeof(setentry)
265 try: # C typedef digit for multi-precision int (or long)
266 _sizeof_Cdigit = long.__itemsize__
267 except NameError: # no long in Python 3.0
268 _sizeof_Cdigit = int.__itemsize__
269 if _sizeof_Cdigit < 2: # pragma: no coverage
270 raise AssertionError('sizeof(%s) bad: %d' % ('digit', _sizeof_Cdigit))
272 # Get character size for internal unicode representation in Python < 3.3
273 try: # sizeof(unicode_char)
274 u = unicode('\0')
275 except NameError: # no unicode() in Python 3.0
276 u = '\0'
277 u = u.encode('unicode-internal') # see .../Lib/test/test_sys.py
278 _sizeof_Cunicode = len(u)
279 del u
281 try: # size of GC header, sizeof(PyGC_Head)
282 import _testcapi as t
283 _sizeof_CPyGC_Head = t.SIZEOF_PYGC_HEAD # new in Python 2.6
284 except (ImportError, AttributeError): # sizeof(PyGC_Head)
285 # alignment should be to sizeof(long double) but there
286 # is no way to obtain that value, assume twice double
287 t = calcsize('2d') - 1
288 _sizeof_CPyGC_Head = (_calcsize('2Pz') + t) & ~t
289 del t
291 # size of refcounts (Python debug build only)
292 if hasattr(sys, 'gettotalrefcount'): # pragma: no coverage
293 _sizeof_Crefcounts = _calcsize('2z')
294 else:
295 _sizeof_Crefcounts = 0
297 try:
298 from abc import ABCMeta
299 except ImportError:
300 class ABCMeta(type):
301 pass
303 # some flags from .../Include/object.h
304 _Py_TPFLAGS_HEAPTYPE = 1 << 9 # Py_TPFLAGS_HEAPTYPE
305 _Py_TPFLAGS_HAVE_GC = 1 << 14 # Py_TPFLAGS_HAVE_GC
307 _Type_type = type(type) # == type and new-style class type
310 # compatibility functions for more uniform
311 # behavior across Python version 2.2 thu 3.0
313 def _items(obj): # dict only
314 '''Return iter-/generator, preferably.
316 return getattr(obj, 'iteritems', obj.items)()
319 def _keys(obj): # dict only
320 '''Return iter-/generator, preferably.
322 return getattr(obj, 'iterkeys', obj.keys)()
325 def _values(obj): # dict only
326 '''Return iter-/generator, preferably.
328 return getattr(obj, 'itervalues', obj.values)()
331 try: # callable() builtin
332 _iscallable = callable
333 except NameError: # callable() removed in Python 3.0
334 def _iscallable(obj):
335 '''Substitute for callable().'''
336 return hasattr(obj, '__call__')
338 # 'cell' is holding data used in closures
339 c = (lambda unused: (lambda: unused))(None)
340 try:
341 _cell_type = type(c.__closure__[0])
342 except AttributeError: # Python 2.5
343 _cell_type = type(c.func_closure[0])
344 del c
346 try:
347 from gc import get_objects as _getobjects # containers only?
348 except ImportError:
349 def _getobjects():
350 # modules first, globals and stack
351 # objects (may contain duplicates)
352 return tuple(_values(sys.modules)) + (
353 globals(), stack(sys.getrecursionlimit())[2:])
355 try: # only used to get referents of
356 # iterators, but gc.get_referents()
357 # returns () for dict...-iterators
358 from gc import get_referents as _getreferents
359 except ImportError:
360 def _getreferents(unused):
361 return () # sorry, no refs
363 # sys.getsizeof() new in Python 2.6, adjusted below
364 _getsizeof = getattr(sys, 'getsizeof', None)
366 try: # str intern()
367 _intern = intern
368 except NameError: # no intern() in Python 3.0
369 def _intern(val):
370 return val
373 # private functions
375 def _basicsize(t, base=0, heap=False, obj=None):
376 '''Get non-zero basicsize of type,
377 including the header sizes.
379 s = max(getattr(t, '__basicsize__', 0), base)
380 # include gc header size
381 if t != _Type_type:
382 h = getattr(t, '__flags__', 0) & _Py_TPFLAGS_HAVE_GC
383 elif heap: # type, allocated on heap
384 h = True
385 else: # None has no __flags__ attr
386 h = getattr(obj, '__flags__', 0) & _Py_TPFLAGS_HEAPTYPE
387 if h:
388 s += _sizeof_CPyGC_Head
389 # include reference counters
390 return s + _sizeof_Crefcounts
393 def _c100(stats):
394 '''Cutoff as percentage.
396 return int((stats - int(stats)) * 100.0 + 0.5)
399 def _classof(obj, dflt=None):
400 '''Return the object's class object.
402 return getattr(obj, '__class__', dflt)
405 def _derive_typedef(typ):
406 '''Return single, existing super type typedef or None.
408 v = [v for v in _values(_typedefs) if _issubclass(typ, v.type)]
409 if len(v) == 1:
410 return v[0]
411 return None
414 def _dir2(obj, pref='', excl=(), slots=None, itor=''):
415 '''Return an attribute name, object 2-tuple for certain
416 attributes or for the ``__slots__`` attributes of the
417 given object, but not both. Any iterator referent
418 objects are returned with the given name if the
419 latter is non-empty.
421 if slots: # __slots__ attrs
422 if hasattr(obj, slots):
423 # collect all inherited __slots__ attrs
424 # from list, tuple, or dict __slots__,
425 # while removing any duplicate attrs
426 s = {}
427 for c in type(obj).mro():
428 for a in getattr(c, slots, ()):
429 if a.startswith('__'):
430 a = '_' + c.__name__ + a
431 if hasattr(obj, a):
432 s.setdefault(a, getattr(obj, a))
433 # assume __slots__ tuple/list
434 # is holding the attr values
435 yield slots, _Slots(s) # _keys(s)
436 for t in _items(s):
437 yield t # attr name, value
438 elif itor: # iterator referents
439 for o in obj: # iter(obj)
440 yield itor, o
441 else: # regular attrs
442 for a in dir(obj):
443 if a.startswith(pref) and hasattr(obj, a) and a not in excl:
444 yield a, getattr(obj, a)
447 def _infer_dict(obj):
448 '''Return True for likely dict object via duck typing.
450 for ats in (('__len__', 'get', 'has_key', 'items', 'keys', 'update', 'values'),
451 ('__len__', 'get', 'has_key', 'iteritems', 'iterkeys', 'itervalues')):
452 if all(_iscallable(getattr(obj, a, None)) for a in ats):
453 return True
454 return False
457 def _iscell(obj):
458 '''Return True if obj is a cell as used in a closure.
460 return isinstance(obj, _cell_type)
463 def _isdictclass(obj):
464 '''Return True for known dict objects.
466 c = _classof(obj)
467 return c and c.__name__ in _dict_classes.get(c.__module__, ())
470 def _isframe(obj):
471 '''Return True for a stack frame object.
473 try: # safe isframe(), see pympler.muppy
474 return isframe(obj)
475 except ReferenceError:
476 return False
479 def _isnamedtuple(obj):
480 '''Named tuples are identified via duck typing:
481 <http://www.gossamer-threads.com/lists/python/dev/1142178>
483 return isinstance(obj, tuple) and hasattr(obj, '_fields')
486 def _isNULL(obj):
487 '''Prevent asizeof(all=True, ...) crash.
489 Sizing gc.get_objects() crashes in Pythonista3 with
490 Python 3.5.1 on iOS due to 1-tuple (<Null>,) object.
492 return isinstance(obj, tuple) and len(obj) == 1 \
493 and repr(obj) == '(<NULL>,)'
496 def _isnumpy(obj):
497 '''Return True for a NumPy arange, array, matrix, etc. instance.
499 if _numpy_types: # see also _len_numpy
500 return isinstance(obj, _numpy_types) or \
501 (_moduleof(_classof(obj)).startswith('numpy') and
502 hasattr(obj, 'nbytes'))
503 return False
506 def _issubclass(sub, sup):
507 '''Safe issubclass().
509 if sup is not object:
510 try:
511 return issubclass(sub, sup)
512 except TypeError:
513 pass
514 return False
517 def _itemsize(t, item=0):
518 '''Get non-zero itemsize of type.
520 # replace zero value with default
521 return getattr(t, '__itemsize__', 0) or item
524 def _kwdstr(**kwds):
525 '''Keyword arguments as a string.
527 return ', '.join(sorted('%s=%r' % kv for kv in _items(kwds)))
530 def _lengstr(obj):
531 '''Object length as a string.
533 n = alen(obj)
534 if n is None: # no len
535 r = ''
536 elif n > _len(obj): # extended
537 r = ' alen %d!' % n
538 else:
539 r = ' alen %d' % n
540 return r
543 def _moduleof(obj, dflt=''):
544 '''Return the object's module name.
546 return getattr(obj, '__module__', dflt)
549 def _nameof(obj, dflt=''):
550 '''Return the name of an object.
552 return getattr(obj, '__name__', dflt)
555 def _objs_opts(objs, all=None, **opts):
556 '''Return given or 'all' objects
557 and the remaining options.
559 if objs: # given objects
560 t = objs
561 elif all in (False, None):
562 t = ()
563 elif all is True: # 'all' objects
564 t = tuple(_getobjects())
565 if sys.platform == 'ios':
566 # remove any tuples containing NULLs
567 t = tuple(o for o in t if not _isNULL(o))
568 else:
569 raise ValueError('invalid option: %s=%r' % ('all', all))
570 return t, opts
573 def _p100(part, total, prec=1):
574 '''Return percentage as string.
576 r = float(total)
577 if r:
578 r = part * 100.0 / r
579 return '%.*f%%' % (prec, r)
580 return 'n/a'
583 def _plural(num):
584 '''Return 's' if plural.
586 if num == 1:
587 s = ''
588 else:
589 s = 's'
590 return s
593 def _power2(n):
594 '''Finds the next power of 2.
596 p2 = 16
597 while n > p2:
598 p2 += p2
599 return p2
602 def _prepr(obj, clip=0):
603 '''Prettify and clip long repr() string.
605 return _repr(obj, clip=clip).strip('<>').replace("'", '') # remove <''>
608 def _printf(fmt, *args, **print3opts):
609 '''Formatted print to sys.stdout or given stream.
611 *print3opts* -- print keyword arguments, like Python 3.+
613 if print3opts: # like Python 3.0
614 f = print3opts.get('file', None) or sys.stdout
615 if args:
616 f.write(fmt % args)
617 else:
618 f.write(fmt)
619 f.write(print3opts.get('end', linesep))
620 if print3opts.get('flush', False):
621 f.flush()
622 elif args:
623 print(fmt % args)
624 else:
625 print(fmt)
628 def _refs(obj, named, *attrs, **kwds):
629 '''Return specific attribute objects of an object.
631 if named:
632 _N = _NamedRef
633 else:
634 def _N(_, o):
635 return o
637 for a in attrs: # cf. inspect.getmembers()
638 if hasattr(obj, a):
639 yield _N(a, getattr(obj, a))
640 if kwds: # kwds are _dir2() args
641 for a, o in _dir2(obj, **kwds):
642 yield _N(a, o)
645 def _repr(obj, clip=80):
646 '''Clips long repr() string.
648 try: # safe repr()
649 r = repr(obj)
650 except Exception:
651 r = 'N/A'
652 if 0 < clip < len(r):
653 h = (clip // 2) - 2
654 if h > 0:
655 r = r[:h] + '....' + r[-h:]
656 return r
659 def _SI(size, K=1024, i='i'):
660 '''Return size as SI string.
662 if 1 < K < size:
663 f = float(size)
664 for si in iter('KMGPTE'):
665 f /= K
666 if f < K:
667 return ' or %.1f %s%sB' % (f, si, i)
668 return ''
671 def _SI2(size, **kwds):
672 '''Return size as regular plus SI string.
674 return str(size) + _SI(size, **kwds)
677 # type-specific referents functions
679 def _cell_refs(obj, named):
680 return _refs(obj, named, 'cell_contents')
683 def _class_refs(obj, named):
684 '''Return specific referents of a class object.
686 return _refs(obj, named, '__class__', '__dict__', '__doc__', '__mro__',
687 '__name__', '__slots__', '__weakref__')
690 def _co_refs(obj, named):
691 '''Return specific referents of a code object.
693 return _refs(obj, named, pref='co_')
696 def _dict_refs(obj, named):
697 '''Return key and value objects of a dict/proxy.
699 try:
700 if named:
701 for k, v in _items(obj):
702 s = str(k)
703 yield _NamedRef('[K] ' + s, k)
704 yield _NamedRef('[V] ' + s + ': ' + _repr(v), v)
705 else:
706 for k, v in _items(obj):
707 yield k
708 yield v
709 except ReferenceError:
710 warnings.warn("Reference error iterating '%s'" % (_classof(obj),))
713 def _enum_refs(obj, named):
714 '''Return specific referents of an enumerate object.
716 return _refs(obj, named, '__doc__')
719 def _exc_refs(obj, named):
720 '''Return specific referents of an Exception object.
722 # .message raises DeprecationWarning in Python 2.6
723 return _refs(obj, named, 'args', 'filename', 'lineno', 'msg', 'text') # , 'message', 'mixed'
726 def _file_refs(obj, named):
727 '''Return specific referents of a file object.
729 return _refs(obj, named, 'mode', 'name')
732 def _frame_refs(obj, named):
733 '''Return specific referents of a frame object.
735 return _refs(obj, named, pref='f_')
738 def _func_refs(obj, named):
739 '''Return specific referents of a function or lambda object.
741 return _refs(obj, named, '__doc__', '__name__', '__code__', '__closure__',
742 pref='func_', excl=('func_globals',))
745 def _gen_refs(obj, named):
746 '''Return the referent(s) of a generator object.
748 # only some gi_frame attrs
749 f = getattr(obj, 'gi_frame', None)
750 return _refs(f, named, 'f_locals', 'f_code')
753 def _im_refs(obj, named):
754 '''Return specific referents of a method object.
756 return _refs(obj, named, '__doc__', '__name__', '__code__', pref='im_')
759 def _inst_refs(obj, named):
760 '''Return specific referents of a class instance.
762 return _refs(obj, named, '__dict__', '__class__', slots='__slots__')
765 def _iter_refs(obj, named):
766 '''Return the referent(s) of an iterator object.
768 r = _getreferents(obj) # special case
769 return _refs(r, named, itor=_nameof(obj) or 'iteref')
772 def _module_refs(obj, named):
773 '''Return specific referents of a module object.
775 # ignore this very module
776 if obj.__name__ == __name__:
777 return ()
778 # module is essentially a dict
779 return _dict_refs(obj.__dict__, named)
782 def _namedtuple_refs(obj, named):
783 '''Return specific referents of obj-as-sequence and slots but exclude dict.
785 for r in _refs(obj, named, '__class__', slots='__slots__'):
786 yield r
787 for r in obj:
788 yield r
791 def _prop_refs(obj, named):
792 '''Return specific referents of a property object.
794 return _refs(obj, named, '__doc__', pref='f')
797 def _seq_refs(obj, unused): # named unused for PyChecker
798 '''Return specific referents of a frozen/set, list, tuple and xrange object.
800 return obj # XXX for r in obj: yield r
803 def _stat_refs(obj, named):
804 '''Return referents of a os.stat object.
806 return _refs(obj, named, pref='st_')
809 def _statvfs_refs(obj, named):
810 '''Return referents of a os.statvfs object.
812 return _refs(obj, named, pref='f_')
815 def _tb_refs(obj, named):
816 '''Return specific referents of a traceback object.
818 return _refs(obj, named, pref='tb_')
821 def _type_refs(obj, named):
822 '''Return specific referents of a type object.
824 return _refs(obj, named, '__dict__', '__doc__', '__mro__',
825 '__name__', '__slots__', '__weakref__')
828 def _weak_refs(obj, unused): # named unused for PyChecker
829 '''Return weakly referent object.
831 try: # ignore 'key' of KeyedRef
832 return (obj(),)
833 except Exception: # XXX ReferenceError
834 return ()
837 _all_refs = (None, _cell_refs, _class_refs, _co_refs, _dict_refs, _enum_refs,
838 _exc_refs, _file_refs, _frame_refs, _func_refs, _gen_refs,
839 _im_refs, _inst_refs, _iter_refs, _module_refs, _namedtuple_refs,
840 _prop_refs, _seq_refs, _stat_refs, _statvfs_refs, _tb_refs,
841 _type_refs, _weak_refs)
844 # type-specific length functions
846 def _len(obj):
847 '''Safe len().
849 try:
850 return len(obj)
851 except TypeError: # no len()
852 return 0
855 def _len_array(obj):
856 '''Array length (in bytes!).
858 return len(obj) * obj.itemsize
861 def _len_bytearray(obj):
862 '''Bytearray size.
864 return obj.__alloc__()
867 def _len_code(obj): # see .../Lib/test/test_sys.py
868 '''Length of code object (stack and variables only).
870 return (obj.co_stacksize + obj.co_nlocals +
871 _len(obj.co_freevars) + _len(obj.co_cellvars) - 1)
874 def _len_dict(obj):
875 '''Dict length in items (estimate).
877 n = len(obj) # active items
878 if n < 6: # ma_smalltable ...
879 n = 0 # ... in basicsize
880 else: # at least one unused
881 n = _power2(n + 1)
882 return n
885 def _len_frame(obj):
886 '''Length of a frame object.
888 c = getattr(obj, 'f_code', None)
889 if c:
890 n = _len_code(c)
891 else:
892 n = 0
893 return n
896 _digit2p2 = 1 << (_sizeof_Cdigit << 3)
897 _digitmax = _digit2p2 - 1 # == (2 * PyLong_MASK + 1)
898 _digitlog = 1.0 / log(_digit2p2)
901 def _len_int(obj):
902 '''Length of multi-precision int (aka long) in digits.
904 if obj:
905 n, i = 1, abs(obj)
906 if i > _digitmax:
907 # no log(x[, base]) in Python 2.2
908 n += int(log(i) * _digitlog)
909 else: # zero
910 n = 0
911 return n
914 def _len_iter(obj):
915 '''Length (hint) of an iterator.
917 n = getattr(obj, '__length_hint__', None)
918 if n:
919 n = n()
920 else: # try len()
921 n = _len(obj)
922 return n
925 def _len_list(obj):
926 '''Length of list (estimate).
928 n = len(obj)
929 # estimate over-allocation
930 if n > 8:
931 n += 6 + (n >> 3)
932 elif n:
933 n += 4
934 return n
937 def _len_module(obj):
938 '''Module length.
940 return _len(obj.__dict__) # _len(dir(obj))
943 def _len_numpy(obj):
944 '''NumPy array, matrix, etc. length (in bytes!).
946 return obj.nbytes # == obj.size * obj.itemsize
949 def _len_set(obj):
950 '''Length of frozen/set (estimate).
952 n = len(obj)
953 if n > 8: # assume half filled
954 n = _power2(n + n - 2)
955 elif n: # at least 8
956 n = 8
957 return n
960 def _len_slice(obj):
961 '''Slice length.
963 try:
964 return ((obj.stop - obj.start + 1) // obj.step)
965 except (AttributeError, TypeError):
966 return 0
969 def _len_slots(obj):
970 '''Slots length.
972 return len(obj) - 1
975 def _len_struct(obj):
976 '''Struct length in bytes.
978 try:
979 return obj.size
980 except AttributeError:
981 return 0
984 def _len_unicode(obj):
985 '''Unicode size.
987 return len(obj) + 1
990 _all_lens = (None, _len, _len_array, _len_bytearray, _len_code,
991 _len_dict, _len_frame, _len_int, _len_iter,
992 _len_list, _len_module, _len_numpy, _len_set,
993 _len_slice, _len_slots, _len_struct, _len_unicode)
995 # more private functions and classes
997 _old_style = '*' # marker
998 _new_style = '' # no marker
1001 class _Claskey(object):
1002 '''Wrapper for class objects.
1004 __slots__ = ('_obj', '_sty')
1006 def __init__(self, obj, style):
1007 self._obj = obj # XXX Weakref.ref(obj)
1008 self._sty = style
1010 def __str__(self):
1011 r = str(self._obj)
1012 if r.endswith('>'):
1013 r = '%s%s def>' % (r[:-1], self._sty)
1014 elif self._sty is _old_style and not r.startswith('class '):
1015 r = 'class %s%s def' % (r, self._sty)
1016 else:
1017 r = '%s%s def' % (r, self._sty)
1018 return r
1019 __repr__ = __str__
1022 # For most objects, the object type is used as the key in the
1023 # _typedefs dict further below, except class and type objects
1024 # and old-style instances. Those are wrapped with separate
1025 # _Claskey or _Instkey instances to be able (1) to distinguish
1026 # instances of different old-style classes by class, (2) to
1027 # distinguish class (and type) instances from class (and type)
1028 # definitions for new-style classes and (3) provide similar
1029 # results for repr() and str() of new- and old-style classes
1030 # and instances.
1032 _claskeys = {} # [id(obj)] = _Claskey()
1035 def _claskey(obj, style):
1036 '''Wraps an old- or new-style class object.
1038 i = id(obj)
1039 k = _claskeys.get(i, None)
1040 if not k:
1041 _claskeys[i] = k = _Claskey(obj, style)
1042 return k
1045 try: # MCCABE 19
1046 # no Class- and InstanceType in Python 3.0
1047 _Types_ClassType = Types.ClassType
1048 _Types_InstanceType = Types.InstanceType
1050 class _Instkey(object):
1051 '''Wrapper for old-style class (instances).
1053 __slots__ = ('_obj',)
1055 def __init__(self, obj):
1056 self._obj = obj # XXX Weakref.ref(obj)
1058 def __str__(self):
1059 t = _moduleof(self._obj), self._obj.__name__, _old_style
1060 return '<class %s.%s%s>' % t
1061 __repr__ = __str__
1063 _instkeys = {} # [id(obj)] = _Instkey()
1065 def _instkey(obj):
1066 '''Wraps an old-style class (instance).
1068 i = id(obj)
1069 k = _instkeys.get(i, None)
1070 if not k:
1071 _instkeys[i] = k = _Instkey(obj)
1072 return k
1074 def _keytuple(obj):
1075 '''Return class and instance keys for a class.
1077 t = type(obj)
1078 if t is _Types_InstanceType:
1079 t = obj.__class__
1080 return _claskey(t, _old_style), _instkey(t)
1081 elif t is _Types_ClassType:
1082 return _claskey(obj, _old_style), _instkey(obj)
1083 elif t is _Type_type:
1084 return _claskey(obj, _new_style), obj
1085 return None, None # not a class
1087 def _objkey(obj):
1088 '''Return the key for any object.
1090 k = type(obj)
1091 if k is _Types_InstanceType:
1092 k = _instkey(obj.__class__)
1093 elif k is _Types_ClassType:
1094 k = _claskey(obj, _old_style)
1095 elif k is _Type_type:
1096 k = _claskey(obj, _new_style)
1097 return k
1099 except AttributeError: # Python 3.0
1101 def _keytuple(obj): # PYCHOK expected
1102 '''Return class and instance keys for a class.
1104 if type(obj) is _Type_type: # isclass(obj):
1105 return _claskey(obj, _new_style), obj
1106 return None, None # not a class
1108 def _objkey(obj): # PYCHOK expected
1109 '''Return the key for any object.
1111 k = type(obj)
1112 if k is _Type_type: # isclass(obj):
1113 k = _claskey(obj, _new_style)
1114 return k
1117 class _NamedRef(object):
1118 '''Store referred object along
1119 with the name of the referent.
1121 __slots__ = ('name', 'ref')
1123 def __init__(self, name, ref):
1124 self.name = name
1125 self.ref = ref
1128 class _Slots(tuple):
1129 '''Wrapper class for __slots__ attribute at
1130 class instances to account for the size
1131 of the __slots__ tuple/list containing
1132 references to the attribute values.
1134 pass
1137 # kinds of _Typedefs
1138 _i = _intern
1139 _all_kinds = (_kind_static, _kind_dynamic, _kind_derived, _kind_ignored, _kind_inferred) = (
1140 _i('static'), _i('dynamic'), _i('derived'), _i('ignored'), _i('inferred'))
1141 del _i
1143 _Not_vari = '' # non-variable item size
1146 class _Typedef(object):
1147 '''Type definition class.
1149 __slots__ = {
1150 'base': 0, # basic size in bytes
1151 'item': 0, # item size in bytes
1152 'alen': None, # or _len_...() function
1153 'refs': None, # or _..._refs() function
1154 'both': None, # both data and code if True, code only if False
1155 'kind': None, # _kind_... value
1156 'type': None, # original type
1157 'vari': None} # item size attr name or _Not_vari
1159 def __init__(self, **kwds):
1160 self.reset(**kwds)
1162 def __lt__(self, unused): # for Python 3.0
1163 return True
1165 def __repr__(self):
1166 return repr(self.args())
1168 def __str__(self):
1169 t = [str(self.base), str(self.item)]
1170 for f in (self.alen, self.refs):
1171 if f:
1172 t.append(f.__name__)
1173 else:
1174 t.append('n/a')
1175 if not self.both:
1176 t.append('(code only)')
1177 return ', '.join(t)
1179 def args(self): # as args tuple
1180 '''Return all attributes as arguments tuple.
1182 return (self.base, self.item, self.alen, self.refs,
1183 self.both, self.kind, self.type)
1185 def dup(self, other=None, **kwds):
1186 '''Duplicate attributes of dict or other typedef.
1188 if other is None:
1189 d = _dict_typedef.kwds()
1190 else:
1191 d = other.kwds()
1192 d.update(kwds)
1193 self.reset(**d)
1195 def flat(self, obj, mask=0):
1196 '''Return the aligned flat size.
1198 s = self.base
1199 if self.alen and self.item > 0: # include items
1200 s += self.alen(obj) * self.item
1201 if _getsizeof: # _getsizeof prevails
1202 s = _getsizeof(obj, s)
1203 if mask: # align
1204 s = (s + mask) & ~mask
1205 return s
1207 def format(self):
1208 '''Return format dict.
1210 i = self.item
1211 if self.vari:
1212 i = 'var'
1213 c = n = ''
1214 if not self.both:
1215 c = ' (code only)'
1216 if self.alen:
1217 n = ' (%s)' % _nameof(self.alen)
1218 return dict(base=self.base, item=i, alen=n, code=c,
1219 kind=self.kind)
1221 def kwds(self):
1222 '''Return all attributes as keywords dict.
1224 return dict(base=self.base, item=self.item,
1225 alen=self.alen, refs=self.refs,
1226 both=self.both, kind=self.kind,
1227 type=self.type, vari=self.vari)
1229 def save(self, t, base=0, heap=False):
1230 '''Saves this typedef plus its class typedef.
1232 c, k = _keytuple(t)
1233 if k and k not in _typedefs: # instance key
1234 _typedefs[k] = self
1235 if c and c not in _typedefs: # class key
1236 if t.__module__ in _builtin_modules:
1237 k = _kind_ignored # default
1238 else:
1239 k = self.kind
1240 _typedefs[c] = _Typedef(base=_basicsize(type(t), base=base, heap=heap),
1241 refs=_type_refs,
1242 both=False, kind=k, type=t)
1243 elif isbuiltin(t) and t not in _typedefs: # array, range, xrange in Python 2.x
1244 _typedefs[t] = _Typedef(base=_basicsize(t, base=base),
1245 both=False, kind=_kind_ignored, type=t)
1246 else:
1247 raise KeyError('asizeof typedef %r bad: %r %r' % (self, (c, k), self.both))
1249 def set(self, safe_len=False, **kwds):
1250 '''Sets one or more attributes.
1252 if kwds: # double check
1253 d = self.kwds()
1254 d.update(kwds)
1255 self.reset(**d)
1256 if safe_len and self.item:
1257 self.alen = _len
1259 def reset(self, base=0, item=0, alen=None, refs=None,
1260 both=True, kind=None, type=None, vari=_Not_vari):
1261 '''Resets all specified attributes.
1263 if base < 0:
1264 raise ValueError('invalid option: %s=%r' % ('base', base))
1265 else:
1266 self.base = base
1267 if item < 0:
1268 raise ValueError('invalid option: %s=%r' % ('item', item))
1269 else:
1270 self.item = item
1271 if alen in _all_lens: # XXX or _iscallable(alen)
1272 self.alen = alen
1273 else:
1274 raise ValueError('invalid option: %s=%r' % ('alen', alen))
1275 if refs in _all_refs: # XXX or _iscallable(refs)
1276 self.refs = refs
1277 else:
1278 raise ValueError('invalid option: %s=%r' % ('refs', refs))
1279 if both in (False, True):
1280 self.both = both
1281 else:
1282 raise ValueError('invalid option: %s=%r' % ('both', both))
1283 if kind in _all_kinds:
1284 self.kind = kind
1285 else:
1286 raise ValueError('invalid option: %s=%r' % ('kind', kind))
1287 self.type = type
1288 self.vari = vari or _Not_vari
1289 if str(self.vari) != self.vari:
1290 raise ValueError('invalid option: %s=%r' % ('vari', vari))
1293 _typedefs = {} # [key] = _Typedef()
1296 def _typedef_both(t, base=0, item=0, alen=None, refs=None,
1297 kind=_kind_static, heap=False, vari=_Not_vari):
1298 '''Adds new typedef for both data and code.
1300 v = _Typedef(base=_basicsize(t, base=base), item=_itemsize(t, item),
1301 refs=refs, alen=alen,
1302 both=True, kind=kind, type=t, vari=vari)
1303 v.save(t, base=base, heap=heap)
1304 return v # for _dict_typedef
1307 def _typedef_code(t, base=0, refs=None, kind=_kind_static, heap=False):
1308 '''Adds new typedef for code only.
1310 v = _Typedef(base=_basicsize(t, base=base),
1311 refs=refs,
1312 both=False, kind=kind, type=t)
1313 v.save(t, base=base, heap=heap)
1314 return v # for _dict_typedef
1317 # static typedefs for data and code types
1318 _typedef_both(complex)
1319 _typedef_both(float)
1320 _typedef_both(list, refs=_seq_refs, alen=_len_list, item=_sizeof_Cvoidp) # sizeof(PyObject*)
1321 _typedef_both(tuple, refs=_seq_refs, alen=_len, item=_sizeof_Cvoidp) # sizeof(PyObject*)
1322 _typedef_both(property, refs=_prop_refs)
1323 _typedef_both(type(Ellipsis))
1324 _typedef_both(type(None))
1326 # _Slots is a special tuple, see _Slots.__doc__
1327 _typedef_both(_Slots, item=_sizeof_Cvoidp,
1328 alen=_len_slots, # length less one
1329 refs=None, # but no referents
1330 heap=True) # plus head
1332 # dict, dictproxy, dict_proxy and other dict-like types
1333 _dict_typedef = _typedef_both(dict, item=_sizeof_CPyDictEntry, alen=_len_dict, refs=_dict_refs)
1334 try: # <type dictproxy> only in Python 2.x
1335 _typedef_both(Types.DictProxyType, item=_sizeof_CPyDictEntry, alen=_len_dict, refs=_dict_refs)
1336 except AttributeError: # XXX any class __dict__ is <type dict_proxy> in Python 3.0?
1337 _typedef_both(type(_Typedef.__dict__), item=_sizeof_CPyDictEntry, alen=_len_dict, refs=_dict_refs)
1338 # other dict-like classes and types may be derived or inferred,
1339 # provided the module and class name is listed here (see functions
1340 # adict, _isdictclass and _infer_dict for further details)
1341 _dict_classes = {'UserDict': ('IterableUserDict', 'UserDict'),
1342 'weakref': ('WeakKeyDictionary', 'WeakValueDictionary')}
1343 try: # <type module> is essentially a dict
1344 _typedef_both(Types.ModuleType, base=_dict_typedef.base,
1345 item=_dict_typedef.item + _sizeof_CPyModuleObject,
1346 alen=_len_module, refs=_module_refs)
1347 except AttributeError: # missing
1348 pass
1350 _getsizeof_excls = () # to adjust _getsizeof
1353 def _getsizeof_excls_add(typ):
1354 global _getsizeof_excls
1355 if typ not in _getsizeof_excls:
1356 _getsizeof_excls += (typ,)
1359 # newer or obsolete types
1360 try:
1361 from array import array # array type
1363 def _array_kwds(obj):
1364 if hasattr(obj, 'itemsize'):
1365 v = 'itemsize'
1366 else:
1367 v = _Not_vari
1368 # since item size varies by the array data type, set
1369 # itemsize to 1 byte and use _len_array in bytes; note,
1370 # function itemsize returns the actual size in bytes
1371 # and function alen returns the length in number of items
1372 return dict(alen=_len_array, item=_sizeof_Cbyte, vari=v)
1374 _typedef_both(array, **_array_kwds(array('d', [])))
1376 v = sys.version_info
1377 _array_excl = (v[0] == 2 and v < (2, 7, 4)) or \
1378 (v[0] == 3 and v < (3, 2, 4))
1379 if _array_excl: # see function _typedef below
1380 _getsizeof_excls_add(array)
1382 del v
1383 except ImportError: # missing
1384 _array_excl = array = None # see function _typedef below
1386 try: # bool has non-zero __itemsize__ in 3.0
1387 _typedef_both(bool)
1388 except NameError: # missing
1389 pass
1391 try: # ignore basestring
1392 _typedef_both(basestring, alen=None)
1393 except NameError: # missing
1394 pass
1396 try:
1397 if isbuiltin(buffer): # Python 2.2
1398 _typedef_both(type(buffer('')), item=_sizeof_Cbyte, alen=_len) # XXX len in bytes?
1399 else:
1400 _typedef_both(buffer, item=_sizeof_Cbyte, alen=_len) # XXX len in bytes?
1401 except NameError: # missing
1402 pass
1404 try:
1405 _typedef_both(bytearray, item=_sizeof_Cbyte, alen=_len_bytearray)
1406 except NameError: # bytearray new in 2.6, 3.0
1407 pass
1408 try:
1409 if type(bytes) is not type(str): # bytes is str in 2.6, bytes new in 2.6, 3.0
1410 _typedef_both(bytes, item=_sizeof_Cbyte, alen=_len) # bytes new in 2.6, 3.0
1411 except NameError: # missing
1412 pass
1413 try: # XXX like bytes
1414 _typedef_both(str8, item=_sizeof_Cbyte, alen=_len) # PYCHOK str8 new in 2.6, 3.0
1415 except NameError: # missing
1416 pass
1418 try:
1419 _typedef_both(enumerate, refs=_enum_refs)
1420 except NameError: # missing
1421 pass
1423 try: # Exception is type in Python 3.0
1424 _typedef_both(Exception, refs=_exc_refs)
1425 except Exception: # missing
1426 pass
1428 try:
1429 _typedef_both(file, refs=_file_refs)
1430 except NameError: # missing
1431 pass
1433 try:
1434 _typedef_both(frozenset, item=_sizeof_Csetentry, alen=_len_set, refs=_seq_refs)
1435 except NameError: # missing
1436 pass
1437 try:
1438 _typedef_both(set, item=_sizeof_Csetentry, alen=_len_set, refs=_seq_refs)
1439 except NameError: # missing
1440 pass
1442 try: # not callable()
1443 _typedef_both(Types.GetSetDescriptorType)
1444 except AttributeError: # missing
1445 pass
1447 try: # if long exists, it is multi-precision ...
1448 _typedef_both(long, item=_sizeof_Cdigit, alen=_len_int)
1449 _typedef_both(int) # ... and int is fixed size
1450 except NameError: # no long, only multi-precision int in Python 3.0
1451 _typedef_both(int, item=_sizeof_Cdigit, alen=_len_int)
1453 try: # not callable()
1454 _typedef_both(Types.MemberDescriptorType)
1455 except AttributeError: # missing
1456 pass
1458 try:
1459 _typedef_both(type(NotImplemented)) # == Types.NotImplementedType
1460 except NameError: # missing
1461 pass
1463 _numpy_types = ()
1464 try:
1465 import numpy # NumPy array, matrix, etc.
1467 def _numpy_kwds(obj):
1468 if _getsizeof:
1469 b = _getsizeof(obj, 96) - obj.nbytes
1470 else:
1471 b = 96 # 96..144 typical __basicsize__?
1472 # since item size depends on the nympy data type, set
1473 # itemsize to 1 byte and use _len_numpy in bytes; note,
1474 # function itemsize returns the actual size in bytes,
1475 # function alen returns the length in number of items
1476 return dict(base=b, item=_sizeof_Cbyte, # not obj.itemsize
1477 alen=_len_numpy,
1478 vari='itemsize')
1480 for d in (numpy.array(range(0)), numpy.arange(0),
1481 numpy.matrix(range(0)), numpy.ma.masked_array([])):
1482 t = type(d)
1483 if t not in _numpy_types:
1484 _numpy_types += (t,)
1485 if _isnumpy(d): # double check
1486 _typedef_both(t, **_numpy_kwds(d))
1487 else:
1488 raise AssertionError('not %s: %r' % ('numpy', d))
1490 # sizing numpy 1.13 arrays works fine, but 1.8 and older
1491 # appears to suffer from sys.getsizeof() bug like array
1492 v = tuple(map(int, numpy.__version__.split('.')))
1493 _numpy_excl = v < (1, 9, 0)
1494 if _numpy_excl: # see function _typedef below
1495 for t in _numpy_types:
1496 _getsizeof_excls_add(t)
1498 del numpy, d, t, v
1499 except ImportError:
1500 _numpy_excl = False # see function _typedef below
1502 try:
1503 _typedef_both(range)
1504 except NameError: # missing
1505 pass
1506 try:
1507 _typedef_both(xrange)
1508 except NameError: # missing
1509 pass
1511 try:
1512 _typedef_both(reversed, refs=_enum_refs)
1513 except NameError: # missing
1514 pass
1516 try:
1517 _typedef_both(slice, item=_sizeof_Cvoidp, alen=_len_slice) # XXX worst-case itemsize?
1518 except NameError: # missing
1519 pass
1521 try:
1522 from os import stat
1523 _typedef_both(type(stat(curdir)), refs=_stat_refs) # stat_result
1524 except ImportError: # missing
1525 pass
1527 try:
1528 from os import statvfs
1529 _typedef_both(type(statvfs(curdir)), refs=_statvfs_refs, # statvfs_result
1530 item=_sizeof_Cvoidp, alen=_len)
1531 except ImportError: # missing
1532 pass
1534 try:
1535 from struct import Struct # only in Python 2.5 and 3.0
1536 _typedef_both(Struct, item=_sizeof_Cbyte, alen=_len_struct) # len in bytes
1537 except ImportError: # missing
1538 pass
1540 try:
1541 _typedef_both(Types.TracebackType, refs=_tb_refs)
1542 except AttributeError: # missing
1543 pass
1545 try:
1546 _typedef_both(unicode, alen=_len_unicode, item=_sizeof_Cunicode)
1547 _typedef_both(str, alen=_len, item=_sizeof_Cbyte) # 1-byte char
1548 except NameError: # str is unicode
1549 _typedef_both(str, alen=_len_unicode, item=_sizeof_Cunicode)
1551 try: # <type 'KeyedRef'>
1552 _typedef_both(Weakref.KeyedRef, refs=_weak_refs, heap=True) # plus head
1553 except AttributeError: # missing
1554 pass
1556 try: # <type 'weakproxy'>
1557 _typedef_both(Weakref.ProxyType)
1558 except AttributeError: # missing
1559 pass
1561 try: # <type 'weakref'>
1562 _typedef_both(Weakref.ReferenceType, refs=_weak_refs)
1563 except AttributeError: # missing
1564 pass
1566 # some other, callable types
1567 _typedef_code(object, kind=_kind_ignored)
1568 _typedef_code(super, kind=_kind_ignored)
1569 _typedef_code(_Type_type, kind=_kind_ignored)
1571 try:
1572 _typedef_code(classmethod, refs=_im_refs)
1573 except NameError:
1574 pass
1575 try:
1576 _typedef_code(staticmethod, refs=_im_refs)
1577 except NameError:
1578 pass
1579 try:
1580 _typedef_code(Types.MethodType, refs=_im_refs)
1581 except NameError:
1582 pass
1584 try: # generator, code only, no len(), not callable()
1585 _typedef_code(Types.GeneratorType, refs=_gen_refs)
1586 except AttributeError: # missing
1587 pass
1589 try: # <type 'weakcallableproxy'>
1590 _typedef_code(Weakref.CallableProxyType, refs=_weak_refs)
1591 except AttributeError: # missing
1592 pass
1594 # any type-specific iterators
1595 s = [_items({}), _keys({}), _values({})]
1596 try: # reversed list and tuples iterators
1597 s.extend([reversed([]), reversed(())])
1598 except NameError: # missing
1599 pass
1601 try: # range iterator
1602 s.append(xrange(1))
1603 except NameError: # missing
1604 pass
1606 try: # callable-iterator
1607 from re import finditer
1608 s.append(finditer('', ''))
1609 except ImportError: # missing
1610 pass
1612 for t in _values(_typedefs):
1613 if t.type and t.alen:
1614 try: # create an (empty) instance
1615 s.append(t.type())
1616 except TypeError:
1617 pass
1618 for t in s:
1619 try:
1620 i = iter(t)
1621 _typedef_both(type(i), alen=_len_iter, refs=_iter_refs, item=0) # no itemsize!
1622 except (KeyError, TypeError): # ignore non-iterables, duplicates, etc.
1623 pass
1624 del i, s, t
1627 if _getsizeof_excls and _getsizeof:
1628 # workaround the sys.getsizeof (and numpy?) bug
1629 def _wraps(sys_sizeof):
1630 def _getsizeof_wrap(obj, *default):
1631 if isinstance(obj, _getsizeof_excls):
1632 try:
1633 return default[0]
1634 except IndexError:
1635 raise TypeError('no default')
1636 else:
1637 return sys_sizeof(obj, *default)
1638 return _getsizeof_wrap
1640 _getsizeof = _wraps(_getsizeof)
1641 del _wraps
1644 def _typedef(obj, derive=False, infer=False): # MCCABE 24
1645 '''Creates a new typedef for an object.
1647 t = type(obj)
1648 v = _Typedef(base=_basicsize(t, obj=obj),
1649 kind=_kind_dynamic, type=t)
1650 # _printf('new %r %r/%r %s', t, _basicsize(t), _itemsize(t), _repr(dir(obj)))
1651 if ismodule(obj): # handle module like dict
1652 v.dup(item=_dict_typedef.item + _sizeof_CPyModuleObject,
1653 alen=_len_module,
1654 refs=_module_refs)
1655 elif _isframe(obj):
1656 v.set(base=_basicsize(t, base=_sizeof_CPyFrameObject, obj=obj),
1657 item=_itemsize(t),
1658 alen=_len_frame,
1659 refs=_frame_refs)
1660 elif iscode(obj):
1661 v.set(base=_basicsize(t, base=_sizeof_CPyCodeObject, obj=obj),
1662 item=_sizeof_Cvoidp,
1663 alen=_len_code,
1664 refs=_co_refs,
1665 both=False) # code only
1666 elif _iscallable(obj):
1667 if isclass(obj): # class or type
1668 v.set(refs=_class_refs,
1669 both=False) # code only
1670 if _moduleof(obj) in _builtin_modules:
1671 v.set(kind=_kind_ignored)
1672 elif isbuiltin(obj): # function or method
1673 v.set(both=False, # code only
1674 kind=_kind_ignored)
1675 elif isfunction(obj):
1676 v.set(refs=_func_refs,
1677 both=False) # code only
1678 elif ismethod(obj):
1679 v.set(refs=_im_refs,
1680 both=False) # code only
1681 elif isclass(t): # callable instance, e.g. SCons,
1682 # handle like any other instance further below
1683 v.set(item=_itemsize(t), safe_len=True,
1684 refs=_inst_refs) # not code only!
1685 else:
1686 v.set(both=False) # code only
1687 elif _issubclass(t, dict):
1688 v.dup(kind=_kind_derived)
1689 elif _isdictclass(obj) or (infer and _infer_dict(obj)):
1690 v.dup(kind=_kind_inferred)
1691 elif _iscell(obj):
1692 v.set(item=_itemsize(t), refs=_cell_refs)
1693 elif _isnamedtuple(obj):
1694 v.set(refs=_namedtuple_refs)
1695 elif _isnumpy(obj): # NumPy data
1696 v.set(**_numpy_kwds(obj))
1697 if _numpy_excl:
1698 _getsizeof_excls_add(t)
1699 elif array and isinstance(obj, array):
1700 v.set(**_array_kwds(obj))
1701 if _array_excl:
1702 _getsizeof_excls_add(t)
1703 elif _moduleof(obj) in _builtin_modules:
1704 v.set(kind=_kind_ignored)
1705 else: # assume an instance of some class
1706 if derive:
1707 p = _derive_typedef(t)
1708 if p: # duplicate parent
1709 v.dup(other=p, kind=_kind_derived)
1710 return v
1711 if _issubclass(t, Exception):
1712 v.set(item=_itemsize(t), safe_len=True,
1713 refs=_exc_refs,
1714 kind=_kind_derived)
1715 elif isinstance(obj, Exception):
1716 v.set(item=_itemsize(t), safe_len=True,
1717 refs=_exc_refs)
1718 else:
1719 v.set(item=_itemsize(t), safe_len=True,
1720 refs=_inst_refs)
1721 return v
1724 class _Prof(object):
1725 '''Internal type profile class.
1727 total = 0 # total size
1728 high = 0 # largest size
1729 number = 0 # number of (unique) objects
1730 objref = None # largest object (weakref)
1731 weak = False # objref is weakref(object)
1733 def __cmp__(self, other):
1734 if self.total < other.total:
1735 return -1
1736 if self.total > other.total:
1737 return +1
1738 if self.number < other.number:
1739 return -1
1740 if self.number > other.number:
1741 return +1
1742 return 0
1744 def __lt__(self, other): # for Python 3.0
1745 return self.__cmp__(other) < 0
1747 def format(self, clip=0, grand=None):
1748 '''Return format dict.
1750 if self.number > 1: # avg., plural
1751 a, p = int(self.total / self.number), 's'
1752 else:
1753 a, p = self.total, ''
1754 o = self.objref
1755 if self.weak: # weakref'd
1756 o = o()
1757 t = _SI2(self.total)
1758 if grand:
1759 t += ' (%s)' % _p100(self.total, grand, prec=0)
1760 return dict(avg=_SI2(a), high=_SI2(self.high),
1761 lengstr=_lengstr(o), obj=_repr(o, clip=clip),
1762 plural=p, total=t)
1764 def update(self, obj, size):
1765 '''Updates this profile.
1767 self.number += 1
1768 self.total += size
1769 if self.high < size: # largest
1770 self.high = size
1771 try: # prefer using weak ref
1772 self.objref, self.weak = Weakref.ref(obj), True
1773 except TypeError:
1774 self.objref, self.weak = obj, False
1777 # public classes
1779 class Asized(object):
1780 '''Stores the results of an **asized** object in the following
1781 4 attributes:
1783 *size* -- total size of the object (including referents)
1785 *flat* -- flat size of the object
1787 *name* -- name or ``repr`` of the object
1789 *refs* -- tuple containing an **Asized** instance for each referent
1791 __slots__ = ('flat', 'name', 'refs', 'size')
1793 def __init__(self, size, flat, refs=(), name=None):
1794 self.size = size # total size
1795 self.flat = flat # flat size
1796 self.name = name # name, repr or None
1797 self.refs = tuple(refs)
1799 def __str__(self):
1800 return 'size %r, flat %r, refs[%d], name %r' % (
1801 self.size, self.flat, len(self.refs), self.name)
1803 def format(self, format='%(name)s size=%(size)d flat=%(flat)d',
1804 detail=-1, order_by='size', indent=''):
1805 '''Formats the size information of the object and of all sized
1806 referents as a string.
1808 *format='%(name)s...'* -- specifies the format string per
1809 instance, valid interpolation parameters are 'name', 'size'
1810 and 'flat'
1812 *detail=-1* -- detail level up to which referents are
1813 printed (-1 for unlimited)
1815 *order_by='size'* -- sort order of referents, valid choices
1816 are 'name', 'size' or 'flat'
1818 *indent=''* -- optional indentation
1820 lines = [indent + (format % dict(size=self.size, flat=self.flat,
1821 name=self.name))]
1822 if detail and self.refs:
1823 refs = sorted(self.refs, key=lambda x: getattr(x, order_by),
1824 reverse=order_by in ('size', 'flat'))
1825 lines += [ref.format(format=format, detail=detail-1, order_by=order_by,
1826 indent=indent+' ') for ref in refs]
1827 return '\n'.join(lines)
1829 def get(self, name, dflt=None):
1830 '''Return the named referent (or *dflt* if not found).
1832 for ref in self.refs:
1833 if name == ref.name:
1834 return ref
1835 return dflt
1838 class Asizer(object):
1839 '''State and options to accumulate sizes.
1841 _align_ = 8
1842 _clip_ = 80
1843 _code_ = False
1844 _derive_ = False
1845 _detail_ = 0 # for Asized only
1846 _infer_ = False
1847 _limit_ = 100
1848 _stats_ = 0
1850 _cutoff = 0 # in percent
1851 _depth = 0 # deepest recursion
1852 _duplicate = 0
1853 _excl_d = None # {}
1854 _ign_d = _kind_ignored
1855 _incl = '' # or ' (incl. code)'
1856 _mask = 7 # see _align_
1857 _missed = 0 # due to errors
1858 _profile = False
1859 _profs = None # {}
1860 _seen = None # {}
1861 _total = 0 # total size
1863 _stream = None # IO stream for printing
1865 def __init__(self, **opts):
1866 '''New **Asizer** accumulator.
1868 See this module documentation for more details. See method
1869 **reset** for all available options and defaults.
1871 self._excl_d = {}
1872 self.reset(**opts)
1874 def _printf(self, fmt, *args, **print3opts):
1875 '''Prints to sys.stdout or the configured stream if any is
1876 specified and if the file keyword argument is not already
1877 set in the **print3opts for this specific call.
1879 if self._stream and not print3opts.get('file', None):
1880 if args:
1881 fmt = fmt % args
1882 _printf(fmt, file=self._stream, **print3opts)
1883 else:
1884 _printf(fmt, *args, **print3opts)
1886 def _clear(self):
1887 '''Clears state.
1889 self._depth = 0 # recursion depth reached
1890 self._duplicate = 0
1891 self._incl = '' # or ' (incl. code)'
1892 self._missed = 0 # due to errors
1893 self._profile = False
1894 self._profs = {}
1895 self._seen = {}
1896 self._total = 0 # total size
1897 for k in _keys(self._excl_d):
1898 self._excl_d[k] = 0
1900 def _nameof(self, obj):
1901 '''Return the object's name.
1903 return _nameof(obj, '') or self._repr(obj)
1905 def _prepr(self, obj):
1906 '''Like **prepr()**.
1908 return _prepr(obj, clip=self._clip_)
1910 def _prof(self, key):
1911 '''Get _Prof object.
1913 p = self._profs.get(key, None)
1914 if not p:
1915 self._profs[key] = p = _Prof()
1916 return p
1918 def _repr(self, obj):
1919 '''Like ``repr()``.
1921 return _repr(obj, clip=self._clip_)
1923 def _sizer(self, obj, deep, sized): # MCCABE 16
1924 '''Sizes an object, recursively.
1926 s, f, i = 0, 0, id(obj)
1927 # skip obj if seen before
1928 # or if ref of a given obj
1929 if i in self._seen:
1930 if deep:
1931 self._seen[i] += 1
1932 if sized:
1933 s = sized(s, f, name=self._nameof(obj))
1934 return s
1935 else:
1936 self._seen[i] = 0
1937 try:
1938 k, rs = _objkey(obj), []
1939 if k in self._excl_d:
1940 self._excl_d[k] += 1
1941 else:
1942 v = _typedefs.get(k, None)
1943 if not v: # new typedef
1944 _typedefs[k] = v = _typedef(obj, derive=self._derive_,
1945 infer=self._infer_)
1946 if (v.both or self._code_) and v.kind is not self._ign_d:
1947 s = f = v.flat(obj, self._mask) # flat size
1948 if self._profile: # profile type
1949 self._prof(k).update(obj, s)
1950 # recurse, but not for nested modules
1951 if v.refs and deep < self._limit_ \
1952 and not (deep and ismodule(obj)):
1953 # add sizes of referents
1954 r, z, d = v.refs, self._sizer, deep + 1
1955 if sized and deep < self._detail_:
1956 # use named referents
1957 for o in r(obj, True):
1958 if isinstance(o, _NamedRef):
1959 t = z(o.ref, d, sized)
1960 t.name = o.name # PYCHOK _sizer
1961 else:
1962 t = z(o, d, sized)
1963 t.name = self._nameof(o)
1964 rs.append(t)
1965 s += t.size # PYCHOK _sizer
1966 else: # no sum(<generator_expression>) in Python 2.2
1967 s += sum(z(o, d, None) for o in r(obj, False))
1968 # recursion depth reached
1969 if self._depth < d:
1970 self._depth = d
1971 self._seen[i] += 1
1972 except RuntimeError: # XXX RecursionLimitExceeded:
1973 self._missed += 1
1974 if sized:
1975 s = sized(s, f, name=self._nameof(obj), refs=rs)
1976 return s
1978 def _sizes(self, objs, sized=None):
1979 '''Return the size or an **Asized** instance for each given
1980 object and the total size. The total includes the size of
1981 any duplicates only once.
1983 self.exclude_refs(*objs) # skip refs to objs
1984 s, t = {}, []
1985 for o in objs:
1986 i = id(o)
1987 if i in s: # duplicate
1988 self._seen[i] += 1
1989 self._duplicate += 1
1990 else:
1991 s[i] = self._sizer(o, 0, sized)
1992 t.append(s[i])
1993 if sized:
1994 s = sum(i.size for i in _values(s))
1995 else:
1996 s = sum(_values(s))
1997 self._total += s # accumulate
1998 return s, tuple(t)
2000 def asized(self, *objs, **opts):
2001 '''Sizes each object and returns an **Asized** instance with
2002 size information and *referents* up to the given detail level
2003 (and with modified options, see method **set**).
2005 If only one object is given, the return value is the **Asized**
2006 instance for that object.
2008 if opts:
2009 self.set(**opts)
2010 _, t = self._sizes(objs, Asized)
2011 if len(t) == 1:
2012 t = t[0]
2013 return t
2015 def asizeof(self, *objs, **opts):
2016 '''Return the combined size of the given objects (with modified
2017 options, see method **set**).
2019 if opts:
2020 self.set(**opts)
2021 s, _ = self._sizes(objs, None)
2022 return s
2024 def asizesof(self, *objs, **opts):
2025 '''Return the individual sizes of the given objects (with
2026 modified options, see method **set**).
2028 if opts:
2029 self.set(**opts)
2030 _, t = self._sizes(objs, None)
2031 return t
2033 def _get_duplicate(self):
2034 '''Number of duplicate objects seen so far.
2036 return self._duplicate
2037 duplicate = property(_get_duplicate, doc=_get_duplicate.__doc__)
2039 def exclude_refs(self, *objs):
2040 '''Excludes any references to the specified objects from sizing.
2042 While any references to the given objects are excluded, the
2043 objects will be sized if specified as positional arguments in
2044 subsequent calls to methods **asizeof** and **asizesof**.
2046 for o in objs:
2047 self._seen.setdefault(id(o), 0)
2049 def exclude_types(self, *objs):
2050 '''Exclude the specified object instances and types from sizing.
2052 All instances and types of the given objects are excluded, even
2053 objects specified as positional arguments in subsequent calls
2054 to methods **asizeof** and **asizesof**.
2056 for o in objs:
2057 for t in _keytuple(o):
2058 if t and t not in self._excl_d:
2059 self._excl_d[t] = 0
2061 def _get_missed(self):
2062 '''Number of objects missed due to errors.
2064 return self._missed
2065 missed = property(_get_missed, doc=_get_missed.__doc__)
2067 def print_profiles(self, w=0, cutoff=0, **print3opts):
2068 '''Prints the profiles above *cutoff* percentage.
2070 The available options and defaults are:
2072 *w=0* -- indentation for each line
2074 *cutoff=0* -- minimum percentage printed
2076 *print3opts* -- print keyword arguments, like Python 3.+
2078 # get the profiles with non-zero size or count
2079 t = [(v, k) for k, v in _items(self._profs) if v.total > 0 or v.number > 1]
2080 if (len(self._profs) - len(t)) < 9: # just show all
2081 t = [(v, k) for k, v in _items(self._profs)]
2082 if t:
2083 s = ''
2084 if self._total:
2085 s = ' (% of grand total)'
2086 c = max(cutoff, self._cutoff)
2087 c = int(c * 0.01 * self._total)
2088 else:
2089 c = 0
2090 self._printf('%s%*d profile%s: total%s, average, and largest flat size%s: largest object',
2091 linesep, w, len(t), _plural(len(t)), s, self._incl, **print3opts)
2092 r = len(t)
2093 for v, k in sorted(t, reverse=True):
2094 s = 'object%(plural)s: %(total)s, %(avg)s, %(high)s: %(obj)s%(lengstr)s' % v.format(self._clip_, self._total)
2095 self._printf('%*d %s %s', w, v.number, self._prepr(k), s, **print3opts)
2096 r -= 1
2097 if r > 1 and v.total < c:
2098 c = max(cutoff, self._cutoff)
2099 self._printf('%+*d profiles below cutoff (%.0f%%)', w, r, c)
2100 break
2101 z = len(self._profs) - len(t)
2102 if z > 0:
2103 self._printf('%+*d %r object%s', w, z, 'zero', _plural(z), **print3opts)
2105 def print_stats(self, objs=(), opts={}, sized=(), sizes=(), stats=3.0, **print3opts):
2106 '''Prints the statistics.
2108 The available options and defaults are:
2110 *w=0* -- indentation for each line
2112 *objs=()* -- optional, list of objects
2114 *opts={}* -- optional, dict of options used
2116 *sized=()* -- optional, tuple of **Asized** instances returned
2118 *sizes=()* -- optional, tuple of sizes returned
2120 *stats=0.0* -- print stats, see function **asizeof**
2122 *print3opts* -- print keyword arguments, like Python 3.+
2124 s = min(opts.get('stats', stats) or 0, self._stats_)
2125 if s > 0: # print stats
2126 t = self._total + self._missed + sum(_values(self._seen))
2127 w = len(str(t)) + 1
2128 t = c = ''
2129 o = _kwdstr(**opts)
2130 if o and objs:
2131 c = ', '
2132 # print header line(s)
2133 if sized and objs:
2134 n = len(objs)
2135 if n > 1:
2136 self._printf('%sasized(...%s%s) ...', linesep, c, o, **print3opts)
2137 for i in range(n): # no enumerate in Python 2.2.3
2138 self._printf('%*d: %s', w - 1, i, sized[i], **print3opts)
2139 else:
2140 self._printf('%sasized(%s): %s', linesep, o, sized, **print3opts)
2141 elif sizes and objs:
2142 self._printf('%sasizesof(...%s%s) ...', linesep, c, o, **print3opts)
2143 for z, o in zip(sizes, objs):
2144 self._printf('%*d bytes%s%s: %s', w, z, _SI(z), self._incl, self._repr(o), **print3opts)
2145 else:
2146 if objs:
2147 t = self._repr(objs)
2148 self._printf('%sasizeof(%s%s%s) ...', linesep, t, c, o, **print3opts)
2149 # print summary
2150 self.print_summary(w=w, objs=objs, **print3opts)
2151 if s > 1: # print profile
2152 self.print_profiles(w=w, cutoff=_c100(s), **print3opts)
2153 if s > 2: # print typedefs
2154 self.print_typedefs(w=w, **print3opts)
2156 def print_summary(self, w=0, objs=(), **print3opts):
2157 '''Prints the summary statistics.
2159 The available options and defaults are:
2161 *w=0* -- indentation for each line
2163 *objs=()* -- optional, list of objects
2165 *print3opts* -- print keyword arguments, like Python 3.+
2167 self._printf('%*d bytes%s%s', w, self._total, _SI(self._total), self._incl, **print3opts)
2168 if self._mask:
2169 self._printf('%*d byte aligned', w, self._mask + 1, **print3opts)
2170 self._printf('%*d byte sizeof(void*)', w, _sizeof_Cvoidp, **print3opts)
2171 n = len(objs or ())
2172 if n > 0:
2173 d = self._duplicate or ''
2174 if d:
2175 d = ', %d duplicate' % self._duplicate
2176 self._printf('%*d object%s given%s', w, n, _plural(n), d, **print3opts)
2177 t = sum(1 for t in _values(self._seen) if t != 0)
2178 self._printf('%*d object%s sized', w, t, _plural(t), **print3opts)
2179 if self._excl_d:
2180 t = sum(_values(self._excl_d))
2181 self._printf('%*d object%s excluded', w, t, _plural(t), **print3opts)
2182 t = sum(_values(self._seen))
2183 self._printf('%*d object%s seen', w, t, _plural(t), **print3opts)
2184 if self._missed > 0:
2185 self._printf('%*d object%s missed', w, self._missed, _plural(self._missed), **print3opts)
2186 if self._depth > 0:
2187 self._printf('%*d deepest recursion', w, self._depth, **print3opts)
2189 def print_typedefs(self, w=0, **print3opts):
2190 '''Prints the types and dict tables.
2192 The available options and defaults are:
2194 *w=0* -- indentation for each line
2196 *print3opts* -- print keyword arguments, like Python 3.+
2198 for k in _all_kinds:
2199 # XXX Python 3.0 doesn't sort type objects
2200 t = [(self._prepr(a), v) for a, v in _items(_typedefs) if v.kind == k and (v.both or self._code_)]
2201 if t:
2202 self._printf('%s%*d %s type%s: basicsize, itemsize, _len_(), _refs()',
2203 linesep, w, len(t), k, _plural(len(t)), **print3opts)
2204 for a, v in sorted(t):
2205 self._printf('%*s %s: %s', w, '', a, v, **print3opts)
2206 # dict and dict-like classes
2207 t = sum(len(v) for v in _values(_dict_classes))
2208 if t:
2209 self._printf('%s%*d dict/-like classes:', linesep, w, t, **print3opts)
2210 for m, v in _items(_dict_classes):
2211 self._printf('%*s %s: %s', w, '', m, self._prepr(v), **print3opts)
2213 def _get_total(self):
2214 '''Total size (in bytes) accumulated so far.
2216 return self._total
2217 total = property(_get_total, doc=_get_total.__doc__)
2219 def reset(self, align=8, clip=80, code=False, derive=False, # PYCHOK too many args
2220 detail=0, ignored=True, infer=False, limit=100, stats=0,
2221 stream=None):
2222 '''Resets the options, state, etc.
2224 The available options and defaults are:
2226 *align=8* -- size alignment
2228 *clip=80* -- clip repr() strings
2230 *code=False* -- incl. (byte)code size
2232 *derive=False* -- derive from super type
2234 *detail=0* -- **Asized** refs level
2236 *ignored=True* -- ignore certain types
2238 *infer=False* -- try to infer types
2240 *limit=100* -- recursion limit
2242 *stats=0.0* -- print statistics, see function **asizeof**
2244 *stream=None* -- output stream for printing
2246 See function **asizeof** for a description of the options.
2248 # options
2249 self._align_ = align
2250 self._clip_ = clip
2251 self._code_ = code
2252 self._derive_ = derive
2253 self._detail_ = detail # for Asized only
2254 self._infer_ = infer
2255 self._limit_ = limit
2256 self._stats_ = stats
2257 self._stream = stream
2258 if ignored:
2259 self._ign_d = _kind_ignored
2260 else:
2261 self._ign_d = None
2262 # clear state
2263 self._clear()
2264 self.set(align=align, code=code, stats=stats)
2266 def set(self, align=None, code=None, detail=None, limit=None, stats=None):
2267 '''Sets some options. See also method **reset**.
2269 Any options not set remain unchanged from the previous setting.
2270 The available options are:
2272 *align* -- size alignment
2274 *code* -- incl. (byte)code size
2276 *detail* -- **Asized** refs level
2278 *limit* -- recursion limit
2280 *stats* -- print statistics, see function **asizeof**
2282 # adjust
2283 if align is not None:
2284 self._align_ = align
2285 if align > 1:
2286 self._mask = align - 1
2287 if (self._mask & align) != 0:
2288 raise ValueError('invalid option: %s=%r' % ('align', align))
2289 else:
2290 self._mask = 0
2291 if code is not None:
2292 self._code_ = code
2293 if code: # incl. (byte)code
2294 self._incl = ' (incl. code)'
2295 if detail is not None:
2296 self._detail_ = detail
2297 if limit is not None:
2298 self._limit_ = limit
2299 if stats is not None:
2300 if stats < 0:
2301 raise ValueError('invalid option: %s=%r' % ('stats', stats))
2302 self._stats_ = s = int(stats)
2303 self._cutoff = _c100(stats)
2304 if s > 1: # profile types
2305 self._profile = True
2306 else:
2307 self._profile = False
2310 # public functions
2312 def adict(*classes):
2313 '''Installs one or more classes to be handled as dict.
2315 a = True
2316 for c in classes:
2317 # if class is dict-like, add class
2318 # name to _dict_classes[module]
2319 if isclass(c) and _infer_dict(c):
2320 t = _dict_classes.get(c.__module__, ())
2321 if c.__name__ not in t: # extend tuple
2322 _dict_classes[c.__module__] = t + (c.__name__,)
2323 else: # not a dict-like class
2324 a = False
2325 return a # all installed if True
2328 _asizer = Asizer()
2331 def asized(*objs, **opts):
2332 '''Return a tuple containing an **Asized** instance for each
2333 object passed as positional argument.
2335 The available options and defaults are:
2337 *align=8* -- size alignment
2339 *clip=80* -- clip repr() strings
2341 *code=False* -- incl. (byte)code size
2343 *derive=False* -- derive from super type
2345 *detail=0* -- **Asized** refs level
2347 *ignored=True* -- ignore certain types
2349 *infer=False* -- try to infer types
2351 *limit=100* -- recursion limit
2353 *stats=0.0* -- print statistics, see function **asizeof**
2355 If only one object is given, the return value is the **Asized**
2356 instance for that object. Otherwise, the length of the returned
2357 tuple matches the number of given objects.
2359 Set *detail* to the desired referents level and *limit* to the
2360 maximum recursion depth.
2362 See function **asizeof** for descriptions of the other options.
2364 if 'all' in opts:
2365 raise KeyError('invalid option: %s=%r' % ('all', opts['all']))
2366 if objs:
2367 _asizer.reset(**opts)
2368 t = _asizer.asized(*objs)
2369 _asizer.print_stats(objs, opts=opts, sized=t) # show opts as _kwdstr
2370 _asizer._clear()
2371 else:
2372 t = ()
2373 return t
2376 def asizeof(*objs, **opts):
2377 '''Return the combined size (in bytes) of all objects passed
2378 as positional arguments.
2380 The available options and defaults are:
2382 *align=8* -- size alignment
2384 *all=False* -- all current objects
2386 *clip=80* -- clip ``repr()`` strings
2388 *code=False* -- incl. (byte)code size
2390 *derive=False* -- derive from super type
2392 *ignored=True* -- ignore certain types
2394 *infer=False* -- try to infer types
2396 *limit=100* -- recursion limit
2398 *stats=0.0* -- print statistics
2400 Set *align* to a power of 2 to align sizes. Any value less
2401 than 2 avoids size alignment.
2403 If *all* is True and if no positional arguments are supplied.
2404 size all current gc objects, including module, global and stack
2405 frame objects.
2407 A positive *clip* value truncates all repr() strings to at
2408 most *clip* characters.
2410 The (byte)code size of callable objects like functions,
2411 methods, classes, etc. is included only if *code* is True.
2413 If *derive* is True, new types are handled like an existing
2414 (super) type provided there is one and only of those.
2416 By default certain base types like object, super, etc. are
2417 ignored. Set *ignored* to False to include those.
2419 If *infer* is True, new types are inferred from attributes
2420 (only implemented for dict types on callable attributes
2421 as get, has_key, items, keys and values).
2423 Set *limit* to a positive value to accumulate the sizes of
2424 the referents of each object, recursively up to the limit.
2425 Using *limit=0* returns the sum of the flat[4] sizes of
2426 the given objects. High *limit* values may cause runtime
2427 errors and miss objects for sizing.
2429 A positive value for *stats* prints up to 8 statistics, (1)
2430 a summary of the number of objects sized and seen, (2) a
2431 simple profile of the sized objects by type and (3+) up to
2432 6 tables showing the static, dynamic, derived, ignored,
2433 inferred and dict types used, found respectively installed.
2434 The fractional part of the *stats* value (x 100) is the
2435 cutoff percentage for simple profiles.
2437 See this module documentation for the definition of flat size.
2439 t, p = _objs_opts(objs, **opts)
2440 if t:
2441 _asizer.reset(**p)
2442 s = _asizer.asizeof(*t)
2443 _asizer.print_stats(objs=t, opts=opts) # show opts as _kwdstr
2444 _asizer._clear()
2445 else:
2446 s = 0
2447 return s
2450 def asizesof(*objs, **opts):
2451 '''Return a tuple containing the size (in bytes) of all objects
2452 passed as positional argments.
2454 The available options and defaults are:
2456 *align=8* -- size alignment
2458 *clip=80* -- clip ``repr()`` strings
2460 *code=False* -- incl. (byte)code size
2462 *derive=False* -- derive from super type
2464 *ignored=True* -- ignore certain types
2466 *infer=False* -- try to infer types
2468 *limit=100* -- recursion limit
2470 *stats=0.0* -- print statistics
2472 See function **asizeof** for a description of the options.
2474 The length of the returned tuple equals the number of given objects.
2476 if 'all' in opts:
2477 raise KeyError('invalid option: %s=%r' % ('all', opts['all']))
2478 if objs: # size given objects
2479 _asizer.reset(**opts)
2480 t = _asizer.asizesof(*objs)
2481 _asizer.print_stats(objs, opts=opts, sizes=t) # show opts as _kwdstr
2482 _asizer._clear()
2483 else:
2484 t = ()
2485 return t
2488 def _typedefof(obj, save=False, **opts):
2489 '''Get the typedef for an object.
2491 k = _objkey(obj)
2492 v = _typedefs.get(k, None)
2493 if not v: # new typedef
2494 v = _typedef(obj, **opts)
2495 if save:
2496 _typedefs[k] = v
2497 return v
2500 def alen(obj, **opts):
2501 '''Return the length of an object (in *items*).
2503 See function **basicsize** for a description of the options.
2505 n = t = _typedefof(obj, **opts)
2506 if t:
2507 n = t.alen
2508 if n and _iscallable(n):
2509 i, v, n = t.item, t.vari, n(obj)
2510 if v and i == _sizeof_Cbyte:
2511 i = getattr(obj, v, i)
2512 if i > _sizeof_Cbyte:
2513 n = n // i
2514 return n
2517 leng = alen # for backward comptibility
2520 def basicsize(obj, **opts):
2521 '''Return the basic size of an object (in bytes).
2523 The available options and defaults are:
2525 *derive=False* -- derive type from super type
2527 *infer=False* -- try to infer types
2529 *save=False* -- save the type definition if new
2531 b = _typedefof(obj, **opts)
2532 if b:
2533 b = b.base
2534 return b
2537 def flatsize(obj, align=0, **opts):
2538 '''Return the flat size of an object (in bytes), optionally aligned
2539 to a given power of 2.
2541 See function **basicsize** for a description of all other options.
2543 See this module documentation for the definition of *flat size*.
2545 v = _typedefof(obj, **opts)
2546 if v:
2547 if align > 1:
2548 m = align - 1
2549 if (align & m) != 0:
2550 raise ValueError('invalid option: %s=%r' % ('align', align))
2551 else:
2552 m = 0
2553 v = v.flat(obj, mask=m)
2554 return v
2557 def itemsize(obj, **opts):
2558 '''Return the item size of an object (in bytes).
2560 See function **basicsize** for a description of the options.
2562 i = t = _typedefof(obj, **opts)
2563 if t:
2564 i, v = t.item, t.vari
2565 if v and i == _sizeof_Cbyte:
2566 i = getattr(obj, v, i)
2567 return i
2570 def named_refs(obj, **opts):
2571 """Returns (a generator for) all named *referents* of an object
2572 (re-using functionality from **asizeof**).
2574 See function **basicsize** for a description of the options.
2576 Does not return un-named *referents*, e.g. objects in a list.
2578 t = _typedefof(obj, **opts)
2579 if t:
2580 r = t.refs
2581 if r and _iscallable(r):
2582 for nr in r(obj, True):
2583 try:
2584 yield nr.name, nr.ref
2585 except AttributeError:
2586 pass
2589 def refs(obj, **opts):
2590 '''Return (a generator for) specific *referents* of an object.
2592 See function **basicsize** for a description of the options.
2594 r = t = _typedefof(obj, **opts)
2595 if t:
2596 r = t.refs
2597 if r and _iscallable(r):
2598 r = r(obj, False)
2599 return r
2602 if __name__ == '__main__':
2604 if '-types' in sys.argv: # print static _typedefs
2605 n = len(_typedefs)
2606 w = len(str(n)) * ' '
2607 _printf('%s%d type definitions: %s and %s, kind ... %s', linesep,
2608 n, 'basic-', 'itemsize (alen)', '-type[def]s')
2609 for k, v in sorted((_prepr(k), v) for k, v in _items(_typedefs)):
2610 s = '%(base)s and %(item)s%(alen)s, %(kind)s%(code)s' % v.format()
2611 _printf('%s %s: %s', w, k, s)
2613 else:
2614 if '-gc' in sys.argv:
2615 try:
2616 import gc # PYCHOK expected
2617 gc.collect()
2618 except ImportError:
2619 pass
2621 # just an example
2622 asizeof(all=True, stats=2) # print summary
2624 if '-v' in sys.argv:
2625 print('\n%s %s (Python %s)' % (__file__, __version__, sys.version.split()[0]))
2627 # License from the initial version of this source file follows:
2629 # --------------------------------------------------------------------
2630 # Copyright (c) 2002-2017 -- ProphICy Semiconductor, Inc.
2631 # All rights reserved.
2633 # Redistribution and use in source and binary forms, with or without
2634 # modification, are permitted provided that the following conditions
2635 # are met:
2637 # - Redistributions of source code must retain the above copyright
2638 # notice, this list of conditions and the following disclaimer.
2640 # - Redistributions in binary form must reproduce the above copyright
2641 # notice, this list of conditions and the following disclaimer in
2642 # the documentation and/or other materials provided with the
2643 # distribution.
2645 # - Neither the name of ProphICy Semiconductor, Inc. nor the names
2646 # of its contributors may be used to endorse or promote products
2647 # derived from this software without specific prior written
2648 # permission.
2650 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2651 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2652 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2653 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2654 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2655 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2656 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2657 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2658 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2659 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2660 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
2661 # OF THE POSSIBILITY OF SUCH DAMAGE.
2662 # --------------------------------------------------------------------