# mypy: ignore-errors
"""
This is a stripped-down of asizeof.py from the pympler module. It's vendored
because pympler is unmaintained, while having a critical vulnerability.
Differences from the original asizeof module:
- Removed code for running as __main__
- Removed `adict`
- `__all__` only includes `asizeof`
The *original* original copyright, license and disclaimer are at the end of this
file, exactly as they appeared in the pympler code. pympler itself is under the
Apache license, which appears in the project root.
The original module docstring that appears in pympler follows; note that some of
it no longer pertains here, but it's preserved to document implementation
details.
"""
"""
**Public Functions** [#unsafe]_
Function **asizesof** returns a tuple containing the (approximate)
size in bytes for each given Python object separately.
Function **asized** returns for each object an instance of class
**Asized** containing all the size information of the object and
a tuple with the referents [#refs]_.
Functions **basicsize** and **itemsize** return the *basic-*
respectively *itemsize* of the given object, both in bytes. For
objects as ``array.array``, ``numpy.array``, ``numpy.ndarray``,
etc. where the item size varies depending on the instance-specific
data type, function **itemsize** returns that item size.
Function **flatsize** returns the *flat size* of a Python object
in bytes defined as the *basic size* plus the *item size* times
the *length* of the given object.
Function **leng** returns the *length* of an object, like standard
function ``len`` but extended for several types. E.g. the **leng**
of a multi-precision int (formerly long) is the number of ``digits``
[#digit]_. The length of most *mutable* sequence objects includes
an estimate of the over-allocation and therefore, the **leng** value
may differ from the standard ``len`` result. For objects like
``array.array``, ``numpy.array``, ``numpy.ndarray``, etc. function
**leng** returns the proper number of items.
Function **refs** returns (a generator for) the referents [#refs]_
of the given object.
**Public Classes** [#unsafe]_
Class **Asizer** may be used to accumulate the results of several
**asizeof** or **asizesof** calls. After creating an **Asizer**
instance, use methods **asizeof** and **asizesof** as needed to
size any number of additional objects.
Call methods **exclude_refs** and/or **exclude_types** to exclude
references to respectively instances or types of certain objects.
Use one of the **print\\_...** methods to report the statistics.
An instance of class **Asized** is returned for each object sized
by the **asized** function or method.
**Duplicate Objects**
Any duplicate, given objects are sized only once and the size
is included in the accumulated total only once. But functions
**asizesof** and **asized** will return a size value respectively
an **Asized** instance for each given object, including duplicates.
**Definitions** [#arb]_
The *length* of an objects like ``dict``, ``list``, ``set``,
``str``, ``tuple``, etc. is defined as the number of items held
in or allocated by the object. Held items are *references* to
other objects, called the *referents*.
The *size* of an object is defined as the sum of the *flat size*
of the object plus the sizes of any referents [#refs]_. Referents
are visited recursively up to the specified detail level. However,
the size of objects referenced multiple times is included only once
in the total *size*.
The *flat size* of an object is defined as the *basic size* of the
object plus the *item size* times the number of allocated *items*,
*references* to referents. The *flat size* does include the size
for the *references* to the referents, but not the size of the
referents themselves.
The *flat size* returned by function *flatsize* equals the result
of function *asizeof* with options *code=True*, *ignored=False*,
*limit=0* and option *align* set to the same value.
The accurate *flat size* for an object is obtained from function
``sys.getsizeof()`` where available. Otherwise, the *length* and
*size* of sequence objects as ``dicts``, ``lists``, ``sets``, etc.
is based on an estimate for the number of allocated items. As a
result, the reported *length* and *size* may differ substantially
from the actual *length* and *size*.
The *basic* and *item size* are obtained from the ``__basicsize__``
respectively ``__itemsize__`` attributes of the (type of the)
object. Where necessary (e.g. sequence objects), a zero
``__itemsize__`` is replaced by the size of a corresponding C type.
The overhead for Python's garbage collector (GC) is included in
the *basic size* of (GC managed) objects as well as the space
needed for ``refcounts`` (used only in certain Python builds).
Optionally, size values can be aligned to any power-of-2 multiple.
**Size of (byte)code**
The *(byte)code size* of objects like classes, functions, methods,
modules, etc. can be included by setting option *code=True*.
Iterators are handled like sequences: iterated object(s) are sized
like *referents* [#refs]_, but only up to the specified level or
recursion *limit* (and only if function ``gc.get_referents()``
returns the referent object of iterators).
Generators are sized as *(byte)code* only, but the objects are
never generated and never sized.
**New-style Classes**
All ``class``, instance and ``type`` objects are handled uniformly
such that instance objects are distinguished from class objects.
Class and type objects are represented as ``<class .... def>``
respectively ``<type ... def>`` where the ``... def`` suffix marks
the *definition object*. Instances of classes are shown as
``<class module.name>`` without the ``... def`` suffix.
**Ignored Objects**
To avoid excessive sizes, several object types are ignored [#arb]_
by default, e.g. built-in functions, built-in types and classes
[#bi]_, function globals and module referents. However, any
instances thereof and module objects will be sized when passed as
given objects. Ignored object types are included unless option
*ignored* is set accordingly.
In addition, many ``__...__`` attributes of callable objects are
ignored [#arb]_, except crucial ones, e.g. class attributes ``__dict__``,
``__doc__``, ``__name__`` and ``__slots__``. For more details, see
the type-specific ``_..._refs()`` and ``_len_...()`` functions below.
.. rubric:: Footnotes
.. [#unsafe] The functions and classes in this module are not thread-safe.
.. [#refs] The *referents* of an object are the objects referenced *by*
that object. For example, the *referents* of a ``list`` are the
objects held in the ``list``, the *referents* of a ``dict`` are
the key and value objects in the ``dict``, etc.
.. [#arb] These definitions and other assumptions are rather arbitrary
and may need corrections or adjustments.
.. [#digit] The C ``sizeof(digit)`` in bytes can be obtained from the
``int.__itemsize__`` attribute or since Python 3.1+ also from
attribute ``sys.int_info.sizeof_digit``. Function **leng**
determines the number of ``digits`` of a multi-precision int.
.. [#bi] All ``type``s and ``class``es in modules named in private set
``_ignored_modules`` are ignored like other, standard built-ins.
"""
import sys
import types as Types
import warnings
import weakref as Weakref
from inspect import isbuiltin, isclass, iscode, isframe, isfunction, ismethod, ismodule
from math import log
from os import curdir, linesep
from struct import calcsize
__all__ = ["asizeof"]
__version__ = "22.06.30"
_NN = ""
_Not_vari = _NN # non-variable item size
# Any classes and types in modules named in set _ignored_modules
# are ignored by