cavisson-pythonagent 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. cavisson_pythonagent-0.0.1.dist-info/METADATA +32 -0
  2. cavisson_pythonagent-0.0.1.dist-info/RECORD +180 -0
  3. cavisson_pythonagent-0.0.1.dist-info/WHEEL +5 -0
  4. cavisson_pythonagent-0.0.1.dist-info/licenses/LICENSE +19 -0
  5. cavisson_pythonagent-0.0.1.dist-info/top_level.txt +1 -0
  6. pythonagent/__init__.py +22 -0
  7. pythonagent/agent/__init__.py +219 -0
  8. pythonagent/agent/internal/__init__.py +1 -0
  9. pythonagent/agent/internal/agent.py +1651 -0
  10. pythonagent/agent/internal/framesinfo.py +152 -0
  11. pythonagent/agent/internal/heap_dump.py +39 -0
  12. pythonagent/agent/internal/intercept_module.py +70 -0
  13. pythonagent/agent/internal/logs.py +122 -0
  14. pythonagent/agent/internal/metadata/__init__.py +0 -0
  15. pythonagent/agent/internal/metadata/agent_meta_data.py +276 -0
  16. pythonagent/agent/internal/proc_compat.py +75 -0
  17. pythonagent/agent/internal/profile.py +47 -0
  18. pythonagent/agent/internal/provider.py +83 -0
  19. pythonagent/agent/internal/thread_dump.py +85 -0
  20. pythonagent/agent/internal/udp.py +245 -0
  21. pythonagent/agent/internal/udp_message.py +800 -0
  22. pythonagent/agent/probes/Instrumentation/__init__.py +340 -0
  23. pythonagent/agent/probes/Instrumentation/find.py +243 -0
  24. pythonagent/agent/probes/Instrumentation/module_version_resolver.py +155 -0
  25. pythonagent/agent/probes/Instrumentation/new_parser.py +64 -0
  26. pythonagent/agent/probes/Instrumentation/parser.py +129 -0
  27. pythonagent/agent/probes/__init__.py +219 -0
  28. pythonagent/agent/probes/base.py +303 -0
  29. pythonagent/agent/probes/cache/__init__.py +51 -0
  30. pythonagent/agent/probes/cache/redis.py +119 -0
  31. pythonagent/agent/probes/cache/redis_asyncio.py +83 -0
  32. pythonagent/agent/probes/coroutines/__init__.py +1 -0
  33. pythonagent/agent/probes/coroutines/asyncio.py +63 -0
  34. pythonagent/agent/probes/elasticdb/__init__.py +7 -0
  35. pythonagent/agent/probes/elasticdb/aelastic.py +54 -0
  36. pythonagent/agent/probes/frameworks/__init__.py +27 -0
  37. pythonagent/agent/probes/frameworks/agentprofiler.py +105 -0
  38. pythonagent/agent/probes/frameworks/aiohttp_web.py +155 -0
  39. pythonagent/agent/probes/frameworks/aisess.py +151 -0
  40. pythonagent/agent/probes/frameworks/asgi.py +340 -0
  41. pythonagent/agent/probes/frameworks/bottle.py +27 -0
  42. pythonagent/agent/probes/frameworks/cherry.py +25 -0
  43. pythonagent/agent/probes/frameworks/django.py +128 -0
  44. pythonagent/agent/probes/frameworks/falcon.py +21 -0
  45. pythonagent/agent/probes/frameworks/fastapi.py +35 -0
  46. pythonagent/agent/probes/frameworks/flask.py +30 -0
  47. pythonagent/agent/probes/frameworks/pyramid.py +56 -0
  48. pythonagent/agent/probes/frameworks/test.py +108 -0
  49. pythonagent/agent/probes/frameworks/tornado_async_web.py +117 -0
  50. pythonagent/agent/probes/frameworks/tornado_web.py +133 -0
  51. pythonagent/agent/probes/frameworks/wsgi.py +353 -0
  52. pythonagent/agent/probes/grpc/__init__.py +76 -0
  53. pythonagent/agent/probes/grpc/client_interceptor.py +132 -0
  54. pythonagent/agent/probes/grpc/server_interceptor.py +129 -0
  55. pythonagent/agent/probes/havoc/__init__.py +0 -0
  56. pythonagent/agent/probes/havoc/custom_memory_stress.py +186 -0
  57. pythonagent/agent/probes/havoc/custom_thread_stress.py +187 -0
  58. pythonagent/agent/probes/havoc/havoc_constants.py +218 -0
  59. pythonagent/agent/probes/havoc/havoc_manager.py +981 -0
  60. pythonagent/agent/probes/http/__init__.py +49 -0
  61. pythonagent/agent/probes/http/aiohttp_client.py +59 -0
  62. pythonagent/agent/probes/http/boto.py +12 -0
  63. pythonagent/agent/probes/http/httplib.py +110 -0
  64. pythonagent/agent/probes/http/httpx_client.py +116 -0
  65. pythonagent/agent/probes/http/requests.py +15 -0
  66. pythonagent/agent/probes/http/tornado_httpclient.py +85 -0
  67. pythonagent/agent/probes/http/urllib3.py +16 -0
  68. pythonagent/agent/probes/langchain/__init__.py +21 -0
  69. pythonagent/agent/probes/langchain/base_tool.py +95 -0
  70. pythonagent/agent/probes/langchain/langchain_community.py +136 -0
  71. pythonagent/agent/probes/langchain/langchain_core.py +32 -0
  72. pythonagent/agent/probes/langchain/langchain_openai.py +110 -0
  73. pythonagent/agent/probes/logging/__init__.py +106 -0
  74. pythonagent/agent/probes/message_brokers/__init__.py +4 -0
  75. pythonagent/agent/probes/message_brokers/pika.py +126 -0
  76. pythonagent/agent/probes/mongodb/__init__.py +6 -0
  77. pythonagent/agent/probes/mongodb/pymongo.py +286 -0
  78. pythonagent/agent/probes/openai/__init__.py +3 -0
  79. pythonagent/agent/probes/openai/openai.py +797 -0
  80. pythonagent/agent/probes/span.py +101 -0
  81. pythonagent/agent/probes/sql/__init__.py +13 -0
  82. pythonagent/agent/probes/sql/botocores3.py +51 -0
  83. pythonagent/agent/probes/sql/dbapi.py +285 -0
  84. pythonagent/agent/probes/sql/dynamodb.py +90 -0
  85. pythonagent/agent/probes/sql/mysql_connector.py +24 -0
  86. pythonagent/agent/probes/sql/mysql_connector_cext.py +24 -0
  87. pythonagent/agent/probes/sql/mysqldb.py +43 -0
  88. pythonagent/agent/probes/sql/psycopg2.py +174 -0
  89. pythonagent/agent/probes/sql/pymysql.py +25 -0
  90. pythonagent/bootstrap/__init__.py +0 -0
  91. pythonagent/bootstrap/cav_gunicorn.py +26 -0
  92. pythonagent/bootstrap/cavagent_lambda_wrapper.py +291 -0
  93. pythonagent/bootstrap/run.py +47 -0
  94. pythonagent/bootstrap/sitecustomize.py +287 -0
  95. pythonagent/cavisson/netdiagnostics/CavAgent/instrumentationprofile.json +26 -0
  96. pythonagent/cavisson/netdiagnostics/CavAgent/interceptor_points.txt +29 -0
  97. pythonagent/cavisson/netdiagnostics/python/CavAgent/instrumentationprofile.json +42 -0
  98. pythonagent/cavisson/netdiagnostics/python/CavAgent/interceptor_points.txt +29 -0
  99. pythonagent/cavisson/netdiagnostics/python/config/ndsettings.conf +6 -0
  100. pythonagent/config.py +279 -0
  101. pythonagent/find.py +72 -0
  102. pythonagent/find_mod_cls_name.py +54 -0
  103. pythonagent/lang.py +131 -0
  104. pythonagent/lib.py +91 -0
  105. pythonagent/main/__init__.py +0 -0
  106. pythonagent/main/pytrace/__init__.py +79 -0
  107. pythonagent/main/pytrace/commands/__init__.py +0 -0
  108. pythonagent/main/pytrace/commands/auto_discovery.py +25 -0
  109. pythonagent/main/pytrace/commands/run.py +401 -0
  110. pythonagent/main/pytrace/pytrace.py +133 -0
  111. pythonagent/main/wsgi.py +6 -0
  112. pythonagent/main.py +27 -0
  113. pythonagent/run.py +46 -0
  114. pythonagent/sqins.py +8 -0
  115. pythonagent/test.py +73 -0
  116. pythonagent/utils.py +168 -0
  117. pythonagent/vendor/__init__.py +0 -0
  118. pythonagent/vendor/pympler/__init__.py +1 -0
  119. pythonagent/vendor/pympler/asizeof.py +2810 -0
  120. pythonagent/vendor/pympler/charts.py +62 -0
  121. pythonagent/vendor/pympler/classtracker.py +590 -0
  122. pythonagent/vendor/pympler/classtracker_stats.py +780 -0
  123. pythonagent/vendor/pympler/garbagegraph.py +80 -0
  124. pythonagent/vendor/pympler/mprofile.py +97 -0
  125. pythonagent/vendor/pympler/muppy.py +275 -0
  126. pythonagent/vendor/pympler/panels.py +115 -0
  127. pythonagent/vendor/pympler/process.py +238 -0
  128. pythonagent/vendor/pympler/py.typed +0 -0
  129. pythonagent/vendor/pympler/refbrowser.py +451 -0
  130. pythonagent/vendor/pympler/refgraph.py +350 -0
  131. pythonagent/vendor/pympler/summary.py +321 -0
  132. pythonagent/vendor/pympler/tracker.py +267 -0
  133. pythonagent/vendor/pympler/util/__init__.py +0 -0
  134. pythonagent/vendor/pympler/util/bottle.py +3809 -0
  135. pythonagent/vendor/pympler/util/compat.py +23 -0
  136. pythonagent/vendor/pympler/util/stringutils.py +77 -0
  137. pythonagent/vendor/pympler/web.py +346 -0
  138. pythonagent/vendor/werkzeug/__init__.py +20 -0
  139. pythonagent/vendor/werkzeug/_compat.py +228 -0
  140. pythonagent/vendor/werkzeug/_internal.py +473 -0
  141. pythonagent/vendor/werkzeug/_reloader.py +341 -0
  142. pythonagent/vendor/werkzeug/datastructures.py +3120 -0
  143. pythonagent/vendor/werkzeug/debug/__init__.py +498 -0
  144. pythonagent/vendor/werkzeug/debug/console.py +218 -0
  145. pythonagent/vendor/werkzeug/debug/repr.py +297 -0
  146. pythonagent/vendor/werkzeug/debug/tbtools.py +628 -0
  147. pythonagent/vendor/werkzeug/exceptions.py +829 -0
  148. pythonagent/vendor/werkzeug/filesystem.py +64 -0
  149. pythonagent/vendor/werkzeug/formparser.py +584 -0
  150. pythonagent/vendor/werkzeug/http.py +1307 -0
  151. pythonagent/vendor/werkzeug/local.py +420 -0
  152. pythonagent/vendor/werkzeug/middleware/__init__.py +25 -0
  153. pythonagent/vendor/werkzeug/middleware/dispatcher.py +66 -0
  154. pythonagent/vendor/werkzeug/middleware/http_proxy.py +219 -0
  155. pythonagent/vendor/werkzeug/middleware/lint.py +408 -0
  156. pythonagent/vendor/werkzeug/middleware/profiler.py +132 -0
  157. pythonagent/vendor/werkzeug/middleware/proxy_fix.py +169 -0
  158. pythonagent/vendor/werkzeug/middleware/shared_data.py +293 -0
  159. pythonagent/vendor/werkzeug/posixemulation.py +117 -0
  160. pythonagent/vendor/werkzeug/routing.py +2210 -0
  161. pythonagent/vendor/werkzeug/security.py +249 -0
  162. pythonagent/vendor/werkzeug/serving.py +1117 -0
  163. pythonagent/vendor/werkzeug/test.py +1123 -0
  164. pythonagent/vendor/werkzeug/testapp.py +241 -0
  165. pythonagent/vendor/werkzeug/urls.py +1138 -0
  166. pythonagent/vendor/werkzeug/useragents.py +202 -0
  167. pythonagent/vendor/werkzeug/utils.py +778 -0
  168. pythonagent/vendor/werkzeug/wrappers/__init__.py +36 -0
  169. pythonagent/vendor/werkzeug/wrappers/accept.py +50 -0
  170. pythonagent/vendor/werkzeug/wrappers/auth.py +33 -0
  171. pythonagent/vendor/werkzeug/wrappers/base_request.py +673 -0
  172. pythonagent/vendor/werkzeug/wrappers/base_response.py +700 -0
  173. pythonagent/vendor/werkzeug/wrappers/common_descriptors.py +341 -0
  174. pythonagent/vendor/werkzeug/wrappers/cors.py +100 -0
  175. pythonagent/vendor/werkzeug/wrappers/etag.py +304 -0
  176. pythonagent/vendor/werkzeug/wrappers/json.py +145 -0
  177. pythonagent/vendor/werkzeug/wrappers/request.py +49 -0
  178. pythonagent/vendor/werkzeug/wrappers/response.py +84 -0
  179. pythonagent/vendor/werkzeug/wrappers/user_agent.py +14 -0
  180. pythonagent/vendor/werkzeug/wsgi.py +1000 -0
@@ -0,0 +1,2810 @@
1
+ #!/usr/bin/env python
2
+
3
+ # Copyright, license and disclaimer are at the very end of this file.
4
+
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>.
10
+
11
+ # Note, objects like ``namedtuples``, ``closure``, and NumPy data
12
+ # ``array``, ``memmap``, ``ndarray``, etc. are only handled by recent
13
+ # versions of this module. Sizing of ``array.array``, ``int`` and
14
+ # ``__slots__`` have been incorrect and property ``Asizer.duplicate``
15
+ # gave incorrect values in previous versions. Several other properties
16
+ # have been added to class ``Asizer`` and the ``print_summary`` method
17
+ # has been updated.
18
+
19
+ '''
20
+ This module exposes 11 functions and 2 classes to obtain lengths and
21
+ sizes of Python objects (for Python 3.6 or later).
22
+
23
+ Earlier versions of this module supported Python versions down to
24
+ Python 2.2. If you are using Python 3.5 or older, please consider
25
+ downgrading Pympler.
26
+
27
+ **Public Functions** [#unsafe]_
28
+
29
+ Function **asizeof** calculates the combined (approximate) size
30
+ in bytes of one or several Python objects.
31
+
32
+ Function **asizesof** returns a tuple containing the (approximate)
33
+ size in bytes for each given Python object separately.
34
+
35
+ Function **asized** returns for each object an instance of class
36
+ **Asized** containing all the size information of the object and
37
+ a tuple with the referents [#refs]_.
38
+
39
+ Functions **basicsize** and **itemsize** return the *basic-*
40
+ respectively *itemsize* of the given object, both in bytes. For
41
+ objects as ``array.array``, ``numpy.array``, ``numpy.ndarray``,
42
+ etc. where the item size varies depending on the instance-specific
43
+ data type, function **itemsize** returns that item size.
44
+
45
+ Function **flatsize** returns the *flat size* of a Python object
46
+ in bytes defined as the *basic size* plus the *item size* times
47
+ the *length* of the given object.
48
+
49
+ Function **leng** returns the *length* of an object, like standard
50
+ function ``len`` but extended for several types. E.g. the **leng**
51
+ of a multi-precision int (formerly long) is the number of ``digits``
52
+ [#digit]_. The length of most *mutable* sequence objects includes
53
+ an estimate of the over-allocation and therefore, the **leng** value
54
+ may differ from the standard ``len`` result. For objects like
55
+ ``array.array``, ``numpy.array``, ``numpy.ndarray``, etc. function
56
+ **leng** returns the proper number of items.
57
+
58
+ Function **refs** returns (a generator for) the referents [#refs]_
59
+ of the given object.
60
+
61
+ Certain classes are known to be sub-classes of or to behave as
62
+ ``dict`` objects. Function **adict** can be used to register
63
+ other class objects to be treated like ``dict``.
64
+
65
+ **Public Classes** [#unsafe]_
66
+
67
+ Class **Asizer** may be used to accumulate the results of several
68
+ **asizeof** or **asizesof** calls. After creating an **Asizer**
69
+ instance, use methods **asizeof** and **asizesof** as needed to
70
+ size any number of additional objects.
71
+
72
+ Call methods **exclude_refs** and/or **exclude_types** to exclude
73
+ references to respectively instances or types of certain objects.
74
+
75
+ Use one of the **print\\_...** methods to report the statistics.
76
+
77
+ An instance of class **Asized** is returned for each object sized
78
+ by the **asized** function or method.
79
+
80
+ **Duplicate Objects**
81
+
82
+ Any duplicate, given objects are sized only once and the size
83
+ is included in the accumulated total only once. But functions
84
+ **asizesof** and **asized** will return a size value respectively
85
+ an **Asized** instance for each given object, including duplicates.
86
+
87
+ **Definitions** [#arb]_
88
+
89
+ The *length* of an objects like ``dict``, ``list``, ``set``,
90
+ ``str``, ``tuple``, etc. is defined as the number of items held
91
+ in or allocated by the object. Held items are *references* to
92
+ other objects, called the *referents*.
93
+
94
+ The *size* of an object is defined as the sum of the *flat size*
95
+ of the object plus the sizes of any referents [#refs]_. Referents
96
+ are visited recursively up to the specified detail level. However,
97
+ the size of objects referenced multiple times is included only once
98
+ in the total *size*.
99
+
100
+ The *flat size* of an object is defined as the *basic size* of the
101
+ object plus the *item size* times the number of allocated *items*,
102
+ *references* to referents. The *flat size* does include the size
103
+ for the *references* to the referents, but not the size of the
104
+ referents themselves.
105
+
106
+ The *flat size* returned by function *flatsize* equals the result
107
+ of function *asizeof* with options *code=True*, *ignored=False*,
108
+ *limit=0* and option *align* set to the same value.
109
+
110
+ The accurate *flat size* for an object is obtained from function
111
+ ``sys.getsizeof()`` where available. Otherwise, the *length* and
112
+ *size* of sequence objects as ``dicts``, ``lists``, ``sets``, etc.
113
+ is based on an estimate for the number of allocated items. As a
114
+ result, the reported *length* and *size* may differ substantially
115
+ from the actual *length* and *size*.
116
+
117
+ The *basic* and *item size* are obtained from the ``__basicsize__``
118
+ respectively ``__itemsize__`` attributes of the (type of the)
119
+ object. Where necessary (e.g. sequence objects), a zero
120
+ ``__itemsize__`` is replaced by the size of a corresponding C type.
121
+
122
+ The overhead for Python's garbage collector (GC) is included in
123
+ the *basic size* of (GC managed) objects as well as the space
124
+ needed for ``refcounts`` (used only in certain Python builds).
125
+
126
+ Optionally, size values can be aligned to any power-of-2 multiple.
127
+
128
+ **Size of (byte)code**
129
+
130
+ The *(byte)code size* of objects like classes, functions, methods,
131
+ modules, etc. can be included by setting option *code=True*.
132
+
133
+ Iterators are handled like sequences: iterated object(s) are sized
134
+ like *referents* [#refs]_, but only up to the specified level or
135
+ recursion *limit* (and only if function ``gc.get_referents()``
136
+ returns the referent object of iterators).
137
+
138
+ Generators are sized as *(byte)code* only, but the objects are
139
+ never generated and never sized.
140
+
141
+ **New-style Classes**
142
+
143
+ All ``class``, instance and ``type`` objects are handled uniformly
144
+ such that instance objects are distinguished from class objects.
145
+
146
+ Class and type objects are represented as ``<class .... def>``
147
+ respectively ``<type ... def>`` where the ``... def`` suffix marks
148
+ the *definition object*. Instances of classes are shown as
149
+ ``<class module.name>`` without the ``... def`` suffix.
150
+
151
+ **Ignored Objects**
152
+
153
+ To avoid excessive sizes, several object types are ignored [#arb]_
154
+ by default, e.g. built-in functions, built-in types and classes
155
+ [#bi]_, function globals and module referents. However, any
156
+ instances thereof and module objects will be sized when passed as
157
+ given objects. Ignored object types are included unless option
158
+ *ignored* is set accordingly.
159
+
160
+ In addition, many ``__...__`` attributes of callable objects are
161
+ ignored [#arb]_, except crucial ones, e.g. class attributes ``__dict__``,
162
+ ``__doc__``, ``__name__`` and ``__slots__``. For more details, see
163
+ the type-specific ``_..._refs()`` and ``_len_...()`` functions below.
164
+
165
+ .. rubric:: Footnotes
166
+ .. [#unsafe] The functions and classes in this module are not thread-safe.
167
+
168
+ .. [#refs] The *referents* of an object are the objects referenced *by*
169
+ that object. For example, the *referents* of a ``list`` are the
170
+ objects held in the ``list``, the *referents* of a ``dict`` are
171
+ the key and value objects in the ``dict``, etc.
172
+
173
+ .. [#arb] These definitions and other assumptions are rather arbitrary
174
+ and may need corrections or adjustments.
175
+
176
+ .. [#digit] The C ``sizeof(digit)`` in bytes can be obtained from the
177
+ ``int.__itemsize__`` attribute or since Python 3.1+ also from
178
+ attribute ``sys.int_info.sizeof_digit``. Function **leng**
179
+ determines the number of ``digits`` of a multi-precision int.
180
+
181
+ .. [#bi] All ``type``s and ``class``es in modules named in private set
182
+ ``_ignored_modules`` are ignored like other, standard built-ins.
183
+ ''' # PYCHOK escape
184
+ import sys
185
+ if sys.version_info < (3, 6, 0):
186
+ raise NotImplementedError('%s requires Python 3.6 or newer' % (__file__,))
187
+
188
+ # from abc import ABCMeta
189
+ from typing import Callable, Dict, List, Set, Union # Optional
190
+
191
+ # all imports listed explicitly to help PyChecker
192
+ from inspect import (isbuiltin, isclass, iscode, isframe, isfunction,
193
+ ismethod, ismodule) # stack
194
+ from math import log
195
+ from os import curdir, linesep
196
+ from struct import calcsize # type/class Struct only in Python 2.5+
197
+ import types as Types
198
+ import warnings
199
+ import weakref as Weakref
200
+
201
+ __all__ = [] # overwritten below
202
+ __version__ = '22.12.07' # 22.06.30
203
+
204
+ _NN = ''
205
+ _Not_vari = _NN # non-variable item size
206
+
207
+ # Any classes and types in modules named in set _ignored_modules
208
+ # are ignored by default, like other built-ins classes and types
209
+ _ignored_modules = {int.__module__, 'types', Exception.__module__, # 'weakref'
210
+ __name__} # inluding this very module
211
+
212
+ # Sizes of some primitive C types
213
+ # XXX len(pack(T, 0)) == Struct(T).size == calcsize(T)
214
+ _sizeof_Cbyte = calcsize('c') # sizeof(unsigned char)
215
+ _sizeof_Clong = calcsize('l') # sizeof(long)
216
+ _sizeof_Cvoidp = calcsize('P') # sizeof(void*)
217
+
218
+ # sizeof(long) != sizeof(ssize_t) on LLP64
219
+ _z_P_L = 'P' if _sizeof_Clong < _sizeof_Cvoidp else 'L'
220
+
221
+
222
+ def _calcsize(fmt):
223
+ '''Like struct.calcsize() but with 'z' for Py_ssize_t.
224
+ '''
225
+ return calcsize(fmt.replace('z', _z_P_L))
226
+
227
+
228
+ # Defaults for some basic sizes with 'z' for C Py_ssize_t
229
+ _sizeof_CPyCodeObject = _calcsize('Pz10P5i0P') # sizeof(PyCodeObject)
230
+ _sizeof_CPyFrameObject = _calcsize('Pzz13P63i0P') # sizeof(PyFrameObject)
231
+ _sizeof_CPyModuleObject = _calcsize('PzP0P') # sizeof(PyModuleObject)
232
+
233
+ # Defaults for some item sizes with 'z' for C Py_ssize_t
234
+ _sizeof_CPyDictEntry = _calcsize('z2P') # sizeof(PyDictEntry)
235
+ _sizeof_Csetentry = _calcsize('lP') # sizeof(setentry)
236
+
237
+ # Get character size for internal unicode representation in Python < 3.3
238
+ u = '\0'.encode('utf-8')
239
+ _sizeof_Cunicode = len(u)
240
+ del u
241
+
242
+ try: # Size of GC header, sizeof(PyGC_Head)
243
+ import _testcapi as t
244
+ _sizeof_CPyGC_Head = t.SIZEOF_PYGC_HEAD # new in Python 2.6
245
+ except (ImportError, AttributeError): # sizeof(PyGC_Head)
246
+ # alignment should be to sizeof(long double) but there
247
+ # is no way to obtain that value, assume twice double
248
+ t = calcsize('2d') - 1
249
+ _sizeof_CPyGC_Head = (_calcsize('2Pz') + t) & ~t
250
+
251
+ # Size of refcounts (Python debug build only)
252
+ t = hasattr(sys, 'gettotalrefcount')
253
+ _sizeof_Crefcounts = _calcsize('2z') if t else 0
254
+ del t
255
+
256
+ # Some flags from .../Include/object.h
257
+ _Py_TPFLAGS_HEAPTYPE = 1 << 9 # Py_TPFLAGS_HEAPTYPE
258
+ _Py_TPFLAGS_HAVE_GC = 1 << 14 # Py_TPFLAGS_HAVE_GC
259
+
260
+ _Type_type = type(type) # == type and (new-style) class type
261
+
262
+ from gc import (get_referents as _getreferents,
263
+ get_objects as _getobjects) # containers only?
264
+
265
+ if sys.platform == 'ios': # Apple iOS
266
+ _gc_getobjects = _getobjects
267
+
268
+ def _getobjects(): # PYCHOK expected
269
+ # avoid Pythonista3/Python 3+ crash
270
+ return tuple(o for o in _gc_getobjects() if not _isNULL(o))
271
+
272
+ _getsizeof = sys.getsizeof # sys.getsizeof() new in Python 2.6
273
+
274
+
275
+ # Compatibility functions for more uniform
276
+ # behavior across Python version 2.2 thu 3+
277
+
278
+ def _items(obj): # dict only
279
+ '''Return iter-/generator, preferably.
280
+ '''
281
+ o = getattr(obj, 'iteritems', obj.items)
282
+ return o() if callable(o) else (o or ())
283
+
284
+
285
+ def _keys(obj): # dict only
286
+ '''Return iter-/generator, preferably.
287
+ '''
288
+ o = getattr(obj, 'iterkeys', obj.keys)
289
+ return o() if callable(o) else (o or ())
290
+
291
+
292
+ def _values(obj): # dict only
293
+ '''Return iter-/generator, preferably.
294
+ '''
295
+ o = getattr(obj, 'itervalues', obj.values)
296
+ return o() if callable(o) else (o or ())
297
+
298
+
299
+ # 'cell' is holding data used in closures
300
+ c = (lambda unused: (lambda: unused))(None)
301
+ _cell_type = type(c.__closure__[0]) # type: ignore
302
+ del c
303
+
304
+
305
+ # Private functions
306
+
307
+ def _basicsize(t, base=0, heap=False, obj=None):
308
+ '''Get non-zero basicsize of type,
309
+ including the header sizes.
310
+ '''
311
+ s = max(getattr(t, '__basicsize__', 0), base)
312
+ # include gc header size
313
+ if t != _Type_type:
314
+ h = getattr(t, '__flags__', 0) & _Py_TPFLAGS_HAVE_GC
315
+ elif heap: # type, allocated on heap
316
+ h = True
317
+ else: # None has no __flags__ attr
318
+ h = getattr(obj, '__flags__', 0) & _Py_TPFLAGS_HEAPTYPE
319
+ if h:
320
+ s += _sizeof_CPyGC_Head
321
+ # include reference counters
322
+ return s + _sizeof_Crefcounts
323
+
324
+
325
+ def _classof(obj, dflt=None):
326
+ '''Return the object's class object.
327
+ '''
328
+ return getattr(obj, '__class__', dflt)
329
+
330
+
331
+ def _derive_typedef(typ):
332
+ '''Return single, existing super type typedef or None.
333
+ '''
334
+ v = [v for v in _values(_typedefs) if _issubclass(typ, v.type)]
335
+ return v[0] if len(v) == 1 else None
336
+
337
+
338
+ def _dir2(obj, pref=_NN, excl=(), slots=None, itor=_NN):
339
+ '''Return an attribute name, object 2-tuple for certain
340
+ attributes or for the ``__slots__`` attributes of the
341
+ given object, but not both. Any iterator referent
342
+ objects are returned with the given name if the
343
+ latter is non-empty.
344
+ '''
345
+ if slots: # __slots__ attrs
346
+ if hasattr(obj, slots):
347
+ # collect all inherited __slots__ attrs
348
+ # from list, tuple, or dict __slots__,
349
+ # while removing any duplicate attrs
350
+ s = {}
351
+ for c in type(obj).mro():
352
+ n = _nameof(c)
353
+ for a in getattr(c, slots, ()):
354
+ if a.startswith('__'):
355
+ a = '_' + n + a
356
+ if hasattr(obj, a):
357
+ s.setdefault(a, getattr(obj, a))
358
+ # assume __slots__ tuple-like is holding the values
359
+ # yield slots, _Slots(s) # _keys(s) ... REMOVED,
360
+ # see _Slots.__doc__ further below
361
+ for t in _items(s):
362
+ yield t # attr name, value
363
+ elif itor: # iterator referents
364
+ for o in obj: # iter(obj)
365
+ yield itor, o
366
+ else: # regular attrs
367
+ for a in dir(obj):
368
+ if a.startswith(pref) and hasattr(obj, a) and a not in excl:
369
+ yield a, getattr(obj, a)
370
+
371
+
372
+ def _infer_dict(obj):
373
+ '''Return True for likely dict object via duck typing.
374
+ '''
375
+ for attrs in (('items', 'keys', 'values'),
376
+ ('iteritems', 'iterkeys', 'itervalues')):
377
+ attrs += '__len__', 'get', 'has_key' # 'update'
378
+ if all(callable(getattr(obj, a, None)) for a in attrs):
379
+ return True
380
+ return False
381
+
382
+
383
+ def _isbuiltin2(typ):
384
+ '''Return True for built-in types as in Python 2.
385
+ '''
386
+ # range is no longer a built-in in Python 3+
387
+ return isbuiltin(typ) or (typ is range)
388
+
389
+
390
+ def _iscell(obj):
391
+ '''Return True if obj is a cell as used in a closure.
392
+ '''
393
+ return isinstance(obj, _cell_type)
394
+
395
+
396
+ def _isdictype(obj):
397
+ '''Return True for known dict objects.
398
+ '''
399
+ c = _classof(obj)
400
+ n = _nameof(c)
401
+ return n and n in _dict_types.get(_moduleof(c), ())
402
+
403
+
404
+ def _isframe(obj):
405
+ '''Return True for a stack frame object.
406
+ '''
407
+ try: # safe isframe(), see pympler.muppy
408
+ return isframe(obj)
409
+ except ReferenceError:
410
+ return False
411
+
412
+
413
+ def _isignored(typ):
414
+ '''Is this a type or class to be ignored?
415
+ '''
416
+ return _moduleof(typ) in _ignored_modules
417
+
418
+
419
+ def _isnamedtuple(obj):
420
+ '''Named tuples are identified via duck typing:
421
+ <http://www.Gossamer-Threads.com/lists/python/dev/1142178>
422
+ '''
423
+ return isinstance(obj, tuple) and hasattr(obj, '_fields')
424
+
425
+
426
+ def _isNULL(obj):
427
+ '''Prevent asizeof(all=True, ...) crash.
428
+
429
+ Sizing gc.get_objects() crashes in Pythonista3 with
430
+ Python 3.5.1 on iOS due to 1-tuple (<Null>,) object,
431
+ see <http://forum.omz-software.com/user/mrjean1>.
432
+ '''
433
+ return isinstance(obj, tuple) and len(obj) == 1 \
434
+ and repr(obj) == '(<NULL>,)'
435
+
436
+
437
+ def _issubclass(obj, Super):
438
+ '''Safe inspect.issubclass() returning None if Super is
439
+ *object* or if obj and Super are not a class or type.
440
+ '''
441
+ if Super is not object:
442
+ try:
443
+ return issubclass(obj, Super)
444
+ except TypeError:
445
+ pass
446
+ return None
447
+
448
+
449
+ def _itemsize(t, item=0):
450
+ '''Get non-zero itemsize of type.
451
+ '''
452
+ # replace zero value with default
453
+ return getattr(t, '__itemsize__', 0) or item
454
+
455
+
456
+ def _kwdstr(**kwds):
457
+ '''Keyword arguments as a string.
458
+ '''
459
+ return ', '.join(sorted('%s=%r' % kv for kv in _items(kwds)))
460
+
461
+
462
+ def _lengstr(obj):
463
+ '''Object length as a string.
464
+ '''
465
+ n = leng(obj)
466
+ if n is None: # no len
467
+ r = _NN
468
+ else:
469
+ x = '!' if n > _len(obj) else _NN # extended
470
+ r = ' leng %d%s' % (n, x)
471
+ return r
472
+
473
+
474
+ def _moduleof(obj, dflt=_NN):
475
+ '''Return the object's module name.
476
+ '''
477
+ return getattr(obj, '__module__', dflt)
478
+
479
+
480
+ def _nameof(obj, dflt=_NN):
481
+ '''Return the name of an object.
482
+ '''
483
+ return getattr(obj, '__name__', dflt)
484
+
485
+
486
+ def _objs_opts_x(where, objs, all=None, **opts):
487
+ '''Return the given or 'all' objects plus
488
+ the remaining options and exclude flag
489
+ '''
490
+ if objs: # given objects
491
+ t, x = objs, False
492
+ elif all in (False, None):
493
+ t, x = (), True
494
+ elif all is True: # 'all' objects
495
+ t, x = _getobjects(), True
496
+ else:
497
+ raise _OptionError(where, all=all)
498
+ return t, opts, x
499
+
500
+
501
+ def _OptionError(where, Error=ValueError, **options):
502
+ '''Format an *Error* instance for invalid *option* or *options*.
503
+ '''
504
+ t = _plural(len(options)), _nameof(where), _kwdstr(**options)
505
+ return Error('invalid option%s: %s(%s)' % t)
506
+
507
+
508
+ def _p100(part, total, prec=1):
509
+ '''Return percentage as string.
510
+ '''
511
+ t = float(total)
512
+ if t > 0:
513
+ p = part * 100.0 / t
514
+ r = '%.*f%%' % (prec, p)
515
+ else:
516
+ r = 'n/a'
517
+ return r
518
+
519
+
520
+ def _plural(num):
521
+ '''Return 's' if *num* is not one.
522
+ '''
523
+ return 's' if num != 1 else _NN
524
+
525
+
526
+ def _power_of_2(n):
527
+ '''Find the next power of 2.
528
+ '''
529
+ p2 = 2**int(log(n, 2))
530
+ while n > p2:
531
+ p2 += p2
532
+ return p2
533
+
534
+
535
+ def _prepr(obj, clip=0):
536
+ '''Prettify and clip long repr() string.
537
+ '''
538
+ return _repr(obj, clip=clip).strip('<>').replace("'", _NN) # remove <''>
539
+
540
+
541
+ def _printf(fmt, *args, **print3options):
542
+ '''Formatted print to sys.stdout or given stream.
543
+
544
+ *print3options* -- some keyword arguments, like Python 3+ print.
545
+ '''
546
+ if print3options: # like Python 3+
547
+ f = print3options.get('file', None) or sys.stdout
548
+ if args:
549
+ f.write(fmt % args)
550
+ else:
551
+ f.write(fmt)
552
+ f.write(print3options.get('end', linesep))
553
+ if print3options.get('flush', False):
554
+ f.flush()
555
+ elif args:
556
+ print(fmt % args)
557
+ else:
558
+ print(fmt)
559
+
560
+
561
+ def _refs(obj, named, *attrs, **kwds):
562
+ '''Return specific attribute objects of an object.
563
+ '''
564
+ if named:
565
+ _N = _NamedRef
566
+ else:
567
+ def _N(unused, o):
568
+ return o
569
+
570
+ for a in attrs: # cf. inspect.getmembers()
571
+ if hasattr(obj, a):
572
+ yield _N(a, getattr(obj, a))
573
+ if kwds: # kwds are _dir2() args
574
+ for a, o in _dir2(obj, **kwds):
575
+ yield _N(a, o)
576
+
577
+
578
+ def _repr(obj, clip=80):
579
+ '''Clip long repr() string.
580
+ '''
581
+ try: # safe repr()
582
+ r = repr(obj).replace(linesep, '\\n')
583
+ except Exception:
584
+ r = 'N/A'
585
+ if len(r) > clip > 0:
586
+ h = (clip // 2) - 2
587
+ if h > 0:
588
+ r = r[:h] + '....' + r[-h:]
589
+ return r
590
+
591
+
592
+ def _SI(size, K=1024, i='i'):
593
+ '''Return size as SI string.
594
+ '''
595
+ if 1 < K <= size:
596
+ f = float(size)
597
+ for si in iter('KMGPTE'):
598
+ f /= K
599
+ if f < K:
600
+ return ' or %.1f %s%sB' % (f, si, i)
601
+ return _NN
602
+
603
+
604
+ def _SI2(size, **kwds):
605
+ '''Return size as regular plus SI string.
606
+ '''
607
+ return str(size) + _SI(size, **kwds)
608
+
609
+
610
+ # Type-specific referents functions
611
+
612
+ def _cell_refs(obj, named):
613
+ try: # handle 'empty' cells
614
+ o = obj.cell_contents
615
+ if named:
616
+ o = _NamedRef('cell_contents', o)
617
+ yield o
618
+ except (AttributeError, ValueError):
619
+ pass
620
+
621
+
622
+ def _class_refs(obj, named):
623
+ '''Return specific referents of a class object.
624
+ '''
625
+ return _refs(obj, named, '__class__', '__doc__', '__mro__',
626
+ '__name__', '__slots__', '__weakref__',
627
+ '__dict__') # __dict__ last
628
+
629
+
630
+ def _co_refs(obj, named):
631
+ '''Return specific referents of a code object.
632
+ '''
633
+ return _refs(obj, named, pref='co_')
634
+
635
+
636
+ def _dict_refs(obj, named):
637
+ '''Return key and value objects of a dict/proxy.
638
+ '''
639
+ try:
640
+ if named:
641
+ for k, v in _items(obj):
642
+ s = str(k)
643
+ yield _NamedRef('[K] ' + s, k)
644
+ s += ': ' + _repr(v)
645
+ yield _NamedRef('[V] ' + s, v)
646
+ else:
647
+ for k, v in _items(obj):
648
+ yield k
649
+ yield v
650
+ except (KeyError, ReferenceError, TypeError) as x:
651
+ warnings.warn("Iterating '%s': %r" % (_classof(obj), x))
652
+
653
+
654
+ def _enum_refs(obj, named):
655
+ '''Return specific referents of an enumerate object.
656
+ '''
657
+ return _refs(obj, named, '__doc__')
658
+
659
+
660
+ def _exc_refs(obj, named):
661
+ '''Return specific referents of an Exception object.
662
+ '''
663
+ # .message raises DeprecationWarning in Python 2.6
664
+ return _refs(obj, named, 'args', 'filename', 'lineno', 'msg', 'text') # , 'message', 'mixed'
665
+
666
+
667
+ def _file_refs(obj, named):
668
+ '''Return specific referents of a file object.
669
+ '''
670
+ return _refs(obj, named, 'mode', 'name')
671
+
672
+
673
+ def _frame_refs(obj, named):
674
+ '''Return specific referents of a frame object.
675
+ '''
676
+ return _refs(obj, named, pref='f_')
677
+
678
+
679
+ def _func_refs(obj, named):
680
+ '''Return specific referents of a function or lambda object.
681
+ '''
682
+ return _refs(obj, named, '__doc__', '__name__', '__code__', '__closure__',
683
+ pref='func_', excl=('func_globals',))
684
+
685
+
686
+ def _gen_refs(obj, named):
687
+ '''Return the referent(s) of a generator (expression) object.
688
+ '''
689
+ # only some gi_frame attrs, but none of
690
+ # the items to keep the generator intact
691
+ f = getattr(obj, 'gi_frame', None)
692
+ return _refs(f, named, 'f_locals', 'f_code')
693
+
694
+
695
+ def _im_refs(obj, named):
696
+ '''Return specific referents of a method object.
697
+ '''
698
+ return _refs(obj, named, '__doc__', '__name__', '__code__', pref='im_')
699
+
700
+
701
+ def _inst_refs(obj, named):
702
+ '''Return specific referents of a class instance.
703
+ '''
704
+ return _refs(obj, named, '__dict__', '__class__', slots='__slots__')
705
+
706
+
707
+ def _iter_refs(obj, named):
708
+ '''Return the referent(s) of an iterator object.
709
+ '''
710
+ r = _getreferents(obj) # special case
711
+ return _refs(r, named, itor=_nameof(obj) or 'iteref')
712
+
713
+
714
+ def _module_refs(obj, named):
715
+ '''Return specific referents of a module object.
716
+ '''
717
+ n = _nameof(obj) == __name__ # i.e. this module
718
+ # ignore this very module, module is essentially a dict
719
+ return () if n else _dict_refs(obj.__dict__, named)
720
+
721
+
722
+ def _namedtuple_refs(obj, named):
723
+ '''Return specific referents of obj-as-sequence and slots but exclude dict.
724
+ '''
725
+ for r in _refs(obj, named, '__class__', slots='__slots__'):
726
+ yield r
727
+ for r in obj:
728
+ yield r
729
+
730
+
731
+ def _prop_refs(obj, named):
732
+ '''Return specific referents of a property object.
733
+ '''
734
+ return _refs(obj, named, '__doc__', pref='f')
735
+
736
+
737
+ def _seq_refs(obj, unused): # named unused for PyChecker
738
+ '''Return specific referents of a frozen/set, list, tuple and xrange object.
739
+ '''
740
+ return obj # XXX for r in obj: yield r
741
+
742
+
743
+ def _stat_refs(obj, named):
744
+ '''Return referents of a os.stat object.
745
+ '''
746
+ return _refs(obj, named, pref='st_')
747
+
748
+
749
+ def _statvfs_refs(obj, named):
750
+ '''Return referents of a os.statvfs object.
751
+ '''
752
+ return _refs(obj, named, pref='f_')
753
+
754
+
755
+ def _tb_refs(obj, named):
756
+ '''Return specific referents of a traceback object.
757
+ '''
758
+ return _refs(obj, named, pref='tb_')
759
+
760
+
761
+ def _type_refs(obj, named):
762
+ '''Return specific referents of a type object.
763
+ '''
764
+ return _refs(obj, named, '__doc__', '__mro__', '__name__',
765
+ '__slots__', '__weakref__', '__dict__')
766
+
767
+
768
+ def _weak_refs(obj, unused): # unused for named
769
+ '''Return weakly referent object.
770
+ '''
771
+ try: # ignore 'key' of KeyedRef
772
+ return (obj(),)
773
+ except Exception: # XXX ReferenceError
774
+ return ()
775
+
776
+
777
+ _all_refs = {None, _cell_refs, _class_refs, _co_refs, _dict_refs, _enum_refs,
778
+ _exc_refs, _file_refs, _frame_refs, _func_refs, _gen_refs,
779
+ _im_refs, _inst_refs, _iter_refs, _module_refs, _namedtuple_refs,
780
+ _prop_refs, _seq_refs, _stat_refs, _statvfs_refs, _tb_refs,
781
+ _type_refs, _weak_refs} # type: Set[Union[None, Callable], ...]
782
+
783
+
784
+ # Type-specific length functions
785
+
786
+ def _len(obj):
787
+ '''Safe len().
788
+ '''
789
+ try:
790
+ return len(obj)
791
+ except TypeError: # no len() nor __len__
792
+ return 0
793
+
794
+
795
+ def _len_bytearray(obj):
796
+ '''Bytearray size.
797
+ '''
798
+ return obj.__alloc__()
799
+
800
+
801
+ def _len_code(obj): # see .../Lib/test/test_sys.py
802
+ '''Length of code object (stack and variables only).
803
+ '''
804
+ return (_len(obj.co_freevars) + obj.co_stacksize +
805
+ _len(obj.co_cellvars) + obj.co_nlocals - 1)
806
+
807
+
808
+ def _len_dict(obj):
809
+ '''Dict length in items (estimate).
810
+ '''
811
+ n = len(obj) # active items
812
+ if n < 6: # ma_smalltable ...
813
+ n = 0 # ... in basicsize
814
+ else: # at least one unused
815
+ n = _power_of_2(n + 1)
816
+ return n
817
+
818
+
819
+ def _len_frame(obj):
820
+ '''Length of a frame object.
821
+ '''
822
+ c = getattr(obj, 'f_code', None)
823
+ return _len_code(c) if c else 0
824
+
825
+
826
+ # _sizeof_Cdigit = sys.int_info.sizeof_digit # sys.int_info in Python 3.1+
827
+ # _bitsof_Cdigit = sys.int_info.bits_per_digit # (_sizeof_Cdigit * 15) // 2
828
+ # _Typedef(int).base = int.__basicsize__ # == _getsizeof(0)
829
+ # _Typedef(int).item = int.__itemsize__ # == _sizeof_Cdigit
830
+
831
+ def _len_int(obj):
832
+ '''Length of *int* (multi-precision, formerly long) in Cdigits.
833
+ '''
834
+ n = _getsizeof(obj, 0) - int.__basicsize__
835
+ return (n // int.__itemsize__) if n > 0 else 0
836
+
837
+
838
+ def _len_iter(obj):
839
+ '''Length (hint) of an iterator.
840
+ '''
841
+ n = getattr(obj, '__length_hint__', None)
842
+ return n() if n and callable(n) else _len(obj)
843
+
844
+
845
+ def _len_list(obj):
846
+ '''Length of list (estimate).
847
+ '''
848
+ n = len(obj)
849
+ # estimate over-allocation
850
+ if n > 8:
851
+ n += 6 + (n >> 3)
852
+ elif n:
853
+ n += 4
854
+ return n
855
+
856
+
857
+ def _len_module(obj):
858
+ '''Module length.
859
+ '''
860
+ return _len(obj.__dict__) # _len(dir(obj))
861
+
862
+
863
+ def _len_set(obj):
864
+ '''Length of frozen/set (estimate).
865
+ '''
866
+ n = len(obj)
867
+ if n > 8: # assume half filled
868
+ n = _power_of_2(n + n - 2)
869
+ elif n: # at least 8
870
+ n = 8
871
+ return n
872
+
873
+
874
+ def _len_slice(obj):
875
+ '''Slice length.
876
+ '''
877
+ try:
878
+ return ((obj.stop - obj.start + 1) // obj.step)
879
+ except (AttributeError, TypeError):
880
+ return 0
881
+
882
+
883
+ # REMOVED, see _Slots.__doc__
884
+ # def _len_slots(obj):
885
+ # '''Slots length.
886
+ # '''
887
+ # return len(obj) - 1
888
+
889
+
890
+ def _len_struct(obj):
891
+ '''Struct length in bytes.
892
+ '''
893
+ try:
894
+ return obj.size
895
+ except AttributeError:
896
+ return 0
897
+
898
+
899
+ def _len_unicode(obj):
900
+ '''Unicode size.
901
+ '''
902
+ return len(obj) + 1
903
+
904
+
905
+ _all_lens = {None, _len, _len_bytearray, _len_code, _len_dict,
906
+ _len_frame, _len_int, _len_iter, _len_list,
907
+ _len_module, _len_set, _len_slice, _len_struct,
908
+ _len_unicode} # type: Set[Union[None, Callable], ...]
909
+
910
+
911
+ # More private functions and classes
912
+
913
+ # _old_style = '*' # marker, OBSOLETE
914
+ # _new_style = _NN # no marker
915
+
916
+ class _Claskey(object):
917
+ '''Wrapper for class objects.
918
+ '''
919
+ __slots__ = ('_obj',) # '_sty'
920
+
921
+ def __init__(self, obj):
922
+ self._obj = obj # XXX Weakref.ref(obj)
923
+ # self._sty = _new_style
924
+
925
+ def __str__(self):
926
+ r = str(self._obj)
927
+ return (r[:-1] + ' def>') if r.endswith('>') else (r + ' def')
928
+
929
+ __repr__ = __str__
930
+
931
+
932
+ # For most objects, the object type is used as the key in the
933
+ # _typedefs dict further below, except class and type objects
934
+ # instances. Those are wrapped with separate _Claskey or
935
+ # _Instkey instances to be able (1) to distinguish class (and
936
+ # type) instances from class (and type) definitions and (2)
937
+ # to provide similar results for repr() and str() of classes
938
+ # and instances.
939
+
940
+ _claskeys = {} # type: Dict[int, _Claskey]
941
+ _NoneNone = None, None # not a class
942
+
943
+
944
+ def _claskey(obj):
945
+ '''Wrap a class object.
946
+ '''
947
+ i = id(obj)
948
+ try:
949
+ k = _claskeys[i]
950
+ except KeyError:
951
+ _claskeys[i] = k = _Claskey(obj)
952
+ return k
953
+
954
+
955
+ def _key2tuple(obj): # PYCHOK expected
956
+ '''Return class and instance keys for a class.
957
+ '''
958
+ t = type(obj) is _Type_type # isclass(obj):
959
+ return (_claskey(obj), obj) if t else _NoneNone
960
+
961
+
962
+ def _objkey(obj): # PYCHOK expected
963
+ '''Return the key for any object.
964
+ '''
965
+ k = type(obj)
966
+ if k is _Type_type: # isclass(obj):
967
+ k = _claskey(obj)
968
+ return k
969
+
970
+
971
+ class _NamedRef(object):
972
+ '''Store referred object along
973
+ with the name of the referent.
974
+ '''
975
+ __slots__ = ('name', 'ref')
976
+
977
+ def __init__(self, name, ref):
978
+ self.name = name
979
+ self.ref = ref
980
+
981
+
982
+ # class _Slots(tuple):
983
+ # '''Wrapper class for __slots__ attribute at class definition.
984
+ # The instance-specific __slots__ attributes are stored in
985
+ # a "tuple-like" space inside the instance, see Luciano
986
+ # Ramalho, "Fluent Python", page 274+, O'Reilly, 2016 or
987
+ # at <http://Books.Google.com/books>, then search for
988
+ # "Fluent Python" "Space Savings with the __slots__".
989
+ # '''
990
+ # pass
991
+
992
+
993
+ # all kinds of _Typedefs
994
+ i = sys.intern # Python 3+
995
+ t = (_kind_static, _kind_dynamic, _kind_derived, _kind_ignored, _kind_inferred) = (
996
+ i('static'), i('dynamic'), i('derived'), i('ignored'), i('inferred'))
997
+ _all_kinds = set(t)
998
+ del i, t
999
+
1000
+
1001
+ class _Typedef(object):
1002
+ '''Type definition class.
1003
+ '''
1004
+ base = 0 # basic size in bytes
1005
+ both = None # both data and code if True, code only if False
1006
+ item = 0 # item size in bytes
1007
+ kind = None # _kind_... value
1008
+ leng = None # _len_...() function or None
1009
+ refs = None # _..._refs() function or None
1010
+ type = None # original type
1011
+ vari = None # item size attr name or _Not_vari
1012
+ xtyp = None # if True, not _getsizeof'd
1013
+
1014
+ def __init__(self, **kwds):
1015
+ self.reset(**kwds)
1016
+
1017
+ def __lt__(self, unused): # for Python 3+
1018
+ return True
1019
+
1020
+ def __repr__(self):
1021
+ return repr(self.args())
1022
+
1023
+ def __str__(self):
1024
+ t = [str(self.base), str(self.item)]
1025
+ for f in (self.leng, self.refs):
1026
+ t.append(_nameof(f) or 'n/a')
1027
+ if not self.both:
1028
+ t.append('(code only)')
1029
+ return ', '.join(t)
1030
+
1031
+ def args(self): # as args tuple
1032
+ '''Return all attributes as arguments tuple.
1033
+ '''
1034
+ return (self.base, self.item, self.leng, self.refs,
1035
+ self.both, self.kind, self.type, self.xtyp)
1036
+
1037
+ def dup(self, other=None, **kwds):
1038
+ '''Duplicate attributes of dict or other typedef.
1039
+ '''
1040
+ t = other or _dict_typedef
1041
+ d = t.kwds()
1042
+ d.update(kwds)
1043
+ self.reset(**d)
1044
+
1045
+ def flat(self, obj, mask=0):
1046
+ '''Return the aligned flat size.
1047
+ '''
1048
+ s = self.base
1049
+ if self.leng and self.item > 0: # include items
1050
+ s += self.leng(obj) * self.item
1051
+ # workaround sys.getsizeof bug for _array types
1052
+ # (in some Python versions) and for other types
1053
+ # with variable .itemsize like numpy.arrays, etc.
1054
+ if not self.xtyp:
1055
+ s = _getsizeof(obj, s)
1056
+ if mask: # alignment mask
1057
+ s = (s + mask) & ~mask
1058
+ # if (mask + 1) & mask:
1059
+ # raise _OptionError(self.flat, mask=mask)
1060
+ return s
1061
+
1062
+ def format(self):
1063
+ '''Return format dict.
1064
+ '''
1065
+ a = _nameof(self.leng)
1066
+ return dict(leng=((' (%s)' % (a,)) if a else _NN),
1067
+ item='var' if self.vari else self.item,
1068
+ code=_NN if self.both else ' (code only)',
1069
+ base= self.base, kind= self.kind)
1070
+
1071
+ def kwds(self):
1072
+ '''Return all attributes as keywords dict.
1073
+ '''
1074
+ return dict(base=self.base, both=self.both, item=self.item,
1075
+ kind=self.kind, leng=self.leng, refs=self.refs,
1076
+ type=self.type, vari=self.vari, xtyp=self.xtyp)
1077
+
1078
+ def reset(self, base=0, item=0, leng=None, refs=None,
1079
+ both=True, kind=None, type=None, vari=_Not_vari,
1080
+ xtyp=False, **extra):
1081
+ '''Reset all specified typedef attributes.
1082
+ '''
1083
+ v = vari or _Not_vari
1084
+ if v != str(v): # attr name
1085
+ e = dict(vari=v)
1086
+ elif base < 0:
1087
+ e = dict(base=base)
1088
+ elif both not in (False, True):
1089
+ e = dict(both=both)
1090
+ elif item < 0:
1091
+ e = dict(item=item)
1092
+ elif kind not in _all_kinds:
1093
+ e = dict(kind=kind)
1094
+ elif leng not in _all_lens: # XXX or not callable(leng)
1095
+ e = dict(leng=leng)
1096
+ elif refs not in _all_refs: # XXX or not callable(refs)
1097
+ e = dict(refs=refs)
1098
+ elif xtyp not in (False, True):
1099
+ e = dict(xtyp=xtyp)
1100
+ elif extra:
1101
+ e = {}
1102
+ else:
1103
+ self.base = base
1104
+ self.both = both
1105
+ self.item = item
1106
+ self.kind = kind
1107
+ self.leng = leng
1108
+ self.refs = refs
1109
+ self.type = type # unchecked, as-is
1110
+ self.vari = v
1111
+ self.xtyp = xtyp
1112
+ return
1113
+ e.update(extra)
1114
+ raise _OptionError(self.reset, **e)
1115
+
1116
+ def save(self, t, base=0, heap=False):
1117
+ '''Save this typedef plus its class typedef.
1118
+ '''
1119
+ c, k = _key2tuple(t)
1120
+ if k and k not in _typedefs: # instance key
1121
+ _typedefs[k] = self
1122
+ if c and c not in _typedefs: # class key
1123
+ b = _basicsize(type(t), base=base, heap=heap)
1124
+ k = _kind_ignored if _isignored(t) else self.kind
1125
+ _typedefs[c] = _Typedef(base=b, both=False,
1126
+ kind=k, type=t, refs=_type_refs)
1127
+ elif t not in _typedefs:
1128
+ if not _isbuiltin2(t): # array, range, xrange in Python 2.x
1129
+ s = ' '.join((self.vari, _moduleof(t), _nameof(t)))
1130
+ s = '%r %s %s' % ((c, k), self.both, s.strip())
1131
+ raise KeyError('typedef %r bad: %s' % (self, s))
1132
+
1133
+ _typedefs[t] = _Typedef(base=_basicsize(t, base=base), both=False,
1134
+ kind=_kind_ignored, type=t)
1135
+
1136
+ def set(self, safe_len=False, **kwds):
1137
+ '''Set one or more attributes.
1138
+ '''
1139
+ if kwds: # double check
1140
+ d = self.kwds()
1141
+ d.update(kwds)
1142
+ self.reset(**d)
1143
+ if safe_len and self.item:
1144
+ self.leng = _len
1145
+
1146
+
1147
+ _typedefs = {} # type: Dict[type, _Typedef]
1148
+
1149
+
1150
+ def _typedef_both(t, base=0, item=0, leng=None, refs=None,
1151
+ kind=_kind_static, heap=False, vari=_Not_vari):
1152
+ '''Add new typedef for both data and code.
1153
+ '''
1154
+ v = _Typedef(base=_basicsize(t, base=base), item=_itemsize(t, item),
1155
+ refs=refs, leng=leng,
1156
+ both=True, kind=kind, type=t, vari=vari)
1157
+ v.save(t, base=base, heap=heap)
1158
+ return v # for _dict_typedef
1159
+
1160
+
1161
+ def _typedef_code(t, base=0, refs=None, kind=_kind_static, heap=False):
1162
+ '''Add new typedef for code only.
1163
+ '''
1164
+ v = _Typedef(base=_basicsize(t, base=base),
1165
+ refs=refs,
1166
+ both=False, kind=kind, type=t)
1167
+ v.save(t, base=base, heap=heap)
1168
+ return v # for _dict_typedef
1169
+
1170
+
1171
+ # Static typedefs for data and code types
1172
+ _typedef_both(complex)
1173
+ _typedef_both(float)
1174
+ _typedef_both(int, leng=_len_int) # see _len_int
1175
+ _typedef_both(list, refs=_seq_refs, leng=_len_list, item=_sizeof_Cvoidp) # sizeof(PyObject*)
1176
+ _typedef_both(tuple, refs=_seq_refs, leng=_len, item=_sizeof_Cvoidp) # sizeof(PyObject*)
1177
+ _typedef_both(property, refs=_prop_refs)
1178
+ _typedef_both(type(Ellipsis))
1179
+ _typedef_both(type(None))
1180
+
1181
+ # _Slots are "tuple-like", REMOVED see _Slots.__doc__
1182
+ # _typedef_both(_Slots, item=_sizeof_Cvoidp,
1183
+ # leng=_len_slots, # length less one
1184
+ # refs=None, # but no referents
1185
+ # heap=True) # plus head
1186
+
1187
+ # dict, dictproxy, dict_proxy and other dict-like types
1188
+ _dict_typedef = _typedef_both(dict, item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs)
1189
+ # XXX any class __dict__ is <type dict_proxy> in Python 3+?
1190
+ _typedef_both(type(_Typedef.__dict__), item=_sizeof_CPyDictEntry, leng=_len_dict, refs=_dict_refs)
1191
+ # other dict-like classes and types may be derived or inferred,
1192
+ # provided the module and class name is listed here (see functions
1193
+ # adict, _isdictype and _infer_dict for further details)
1194
+ _dict_types = dict(UserDict=('IterableUserDict', 'UserDict'),
1195
+ weakref =('WeakKeyDictionary', 'WeakValueDictionary'))
1196
+ try: # <type module> is essentially a dict
1197
+ _typedef_both(Types.ModuleType, base=_dict_typedef.base,
1198
+ item=_dict_typedef.item + _sizeof_CPyModuleObject,
1199
+ leng=_len_module, refs=_module_refs)
1200
+ except AttributeError: # missing
1201
+ pass
1202
+
1203
+
1204
+ # Newer or obsolete types
1205
+ from array import array as _array # array type
1206
+
1207
+
1208
+ def _len_array(obj):
1209
+ '''Array length (in bytes!).
1210
+ '''
1211
+ return len(obj) * obj.itemsize
1212
+
1213
+
1214
+ def _array_kwds(obj):
1215
+ # since item size varies by the array data type, set
1216
+ # itemsize to 1 byte and use _len_array in bytes;
1217
+ # _getsizeof(array) returns array plus base size
1218
+ b = max(56, _getsizeof(obj, 0) - _len_array(obj))
1219
+ return dict(base=b, leng=_len_array, item=_sizeof_Cbyte,
1220
+ vari='itemsize', # array.itemsize
1221
+ xtyp= True) # never _getsizeof'd
1222
+
1223
+
1224
+ _all_lens.add(_len_array) # type: ignore
1225
+
1226
+ try: # bool has non-zero __itemsize__ in 3.0
1227
+ _typedef_both(bool)
1228
+ except NameError: # missing
1229
+ pass
1230
+
1231
+ try:
1232
+ _typedef_both(bytearray, item=_sizeof_Cbyte, leng=_len_bytearray)
1233
+ except NameError: # bytearray new in 2.6, 3.0
1234
+ pass
1235
+ try:
1236
+ if type(bytes) is not type(str): # bytes is str in 2.6, bytes new in 2.6, 3.0
1237
+ _typedef_both(bytes, item=_sizeof_Cbyte, leng=_len) # bytes new in 2.6, 3.0
1238
+ except NameError: # missing
1239
+ pass
1240
+ # try: # XXX like bytes
1241
+ # _typedef_both(str8, item=_sizeof_Cbyte, leng=_len) # str8 new in 2.6, 3.0
1242
+ # except NameError: # missing
1243
+ # pass
1244
+
1245
+ try:
1246
+ _typedef_both(enumerate, refs=_enum_refs)
1247
+ except NameError: # missing
1248
+ pass
1249
+
1250
+ try: # Exception is type in Python 3+
1251
+ _typedef_both(Exception, refs=_exc_refs)
1252
+ except Exception: # missing
1253
+ pass
1254
+
1255
+ try:
1256
+ _typedef_both(frozenset, item=_sizeof_Csetentry, leng=_len_set, refs=_seq_refs)
1257
+ except NameError: # missing
1258
+ pass
1259
+ try:
1260
+ _typedef_both(set, item=_sizeof_Csetentry, leng=_len_set, refs=_seq_refs)
1261
+ except NameError: # missing
1262
+ pass
1263
+
1264
+ try: # not callable()
1265
+ _typedef_both(Types.GetSetDescriptorType)
1266
+ except AttributeError: # missing
1267
+ pass
1268
+
1269
+ try: # not callable()
1270
+ _typedef_both(Types.MemberDescriptorType)
1271
+ except AttributeError: # missing
1272
+ pass
1273
+
1274
+ try:
1275
+ _typedef_both(type(NotImplemented)) # == Types.NotImplementedType
1276
+ except NameError: # missing
1277
+ pass
1278
+
1279
+ try: # MCCABE 19
1280
+ import numpy as _numpy # NumPy array, matrix, etc.
1281
+ try:
1282
+ _numpy_memmap = _numpy.memmap
1283
+ except AttributeError:
1284
+ _numpy_memmap = None
1285
+ try:
1286
+ from mmap import PAGESIZE as _PAGESIZE
1287
+ if _PAGESIZE < 1024:
1288
+ raise ImportError
1289
+ except ImportError:
1290
+ _PAGESIZE = 4096 # 4 KiB, typical
1291
+
1292
+ def _isnumpy(obj):
1293
+ '''Return True for a NumPy arange, array, matrix, memmap, ndarray, etc. instance.
1294
+ '''
1295
+ # not every numpy obj hasattr(obj, 'base')
1296
+ try:
1297
+ if hasattr(obj, 'dtype') and hasattr(obj, 'itemsize') \
1298
+ and hasattr(obj, 'nbytes'):
1299
+ return (_moduleof(_classof(obj)).startswith('numpy') or
1300
+ _moduleof(type(obj)).startswith('numpy'))
1301
+ except (AttributeError, OSError, ValueError): # on iOS/Pythonista
1302
+ pass
1303
+ return False
1304
+
1305
+ def _len_numpy(obj):
1306
+ '''NumPy array, matrix, etc. length (in bytes!).
1307
+ '''
1308
+ return obj.nbytes # == obj.size * obj.itemsize
1309
+
1310
+ def _len_numpy_memmap(obj):
1311
+ '''Approximate NumPy memmap in-memory size (in bytes!).
1312
+ '''
1313
+ nb = int(obj.nbytes * _amapped)
1314
+ # round up to multiple of virtual memory page size
1315
+ return ((nb + _PAGESIZE - 1) // _PAGESIZE) * _PAGESIZE
1316
+
1317
+ def _numpy_kwds(obj):
1318
+ t = type(obj)
1319
+ # .nbytes is included in sys.sizeof size for most numpy
1320
+ # objects except for numpy.memmap (and for the latter it
1321
+ # is the length of the file to be memory-mapped which by
1322
+ # default is the file size less the offset specified)
1323
+ _i, _v = _sizeof_Cbyte, 'itemsize'
1324
+ if t is _numpy_memmap: # isinstance(obj, _numpy_memmap)
1325
+ b, _l, nb = 144, _len_numpy_memmap, 0
1326
+ elif t.__name__ in ('str', 'str_'): # numpy.str Deprecated!
1327
+ # make numpy.str_ behave like Python type str
1328
+ b = 81
1329
+ _l = _len
1330
+ nb = _l(obj)
1331
+ _i = obj.nbytes // nb
1332
+ _v = _Not_vari
1333
+ else: # XXX 96, 128, 144 typical?
1334
+ b, _l, nb = 96, _len_numpy, obj.nbytes
1335
+ # since item size depends on the nympy data type, set
1336
+ # itemsize to 1 byte and use _len_numpy in bytes; note,
1337
+ # function itemsize returns the actual size in bytes,
1338
+ # function leng returns the length in number of items
1339
+ return dict(base=_getsizeof(obj, b + nb) - nb,
1340
+ item=_i, # not obj.itemsize!
1341
+ leng=_l,
1342
+ refs=_numpy_refs,
1343
+ vari=_v, # numpy.itemsize
1344
+ xtyp= True) # never _getsizeof'd
1345
+
1346
+ def _numpy_refs(obj, named):
1347
+ '''Return the .base object for NumPy slices, views, etc.
1348
+ '''
1349
+ return _refs(obj, named, 'base')
1350
+
1351
+ _all_lens.add(_len_numpy) # type: ignore
1352
+ _all_lens.add(_len_numpy_memmap) # type: ignore
1353
+ _all_refs.add(_numpy_refs) # type: ignore
1354
+
1355
+ except ImportError: # no NumPy
1356
+ _numpy = _numpy_kwds = None # type: ignore # see function _typedef below
1357
+
1358
+ def _isnumpy(unused): # PYCHOK expected
1359
+ '''Not applicable, no NumPy.
1360
+ '''
1361
+ return False
1362
+
1363
+ try:
1364
+ _typedef_both(range)
1365
+ except NameError: # missing
1366
+ pass
1367
+
1368
+ try:
1369
+ _typedef_both(reversed, refs=_enum_refs)
1370
+ except NameError: # missing
1371
+ pass
1372
+
1373
+ try:
1374
+ _typedef_both(slice, item=_sizeof_Cvoidp, leng=_len_slice) # XXX worst-case itemsize?
1375
+ except NameError: # missing
1376
+ pass
1377
+
1378
+ try:
1379
+ from os import stat
1380
+ _typedef_both(type(stat(curdir)), refs=_stat_refs) # stat_result
1381
+ except ImportError: # missing
1382
+ pass
1383
+
1384
+ try:
1385
+ from os import statvfs
1386
+ _typedef_both(type(statvfs(curdir)), refs=_statvfs_refs, # statvfs_result
1387
+ item=_sizeof_Cvoidp, leng=_len)
1388
+ except ImportError: # missing
1389
+ pass
1390
+
1391
+ try:
1392
+ from struct import Struct # only in Python 2.5 and 3.0
1393
+ _typedef_both(Struct, item=_sizeof_Cbyte, leng=_len_struct) # len in bytes
1394
+ except ImportError: # missing
1395
+ pass
1396
+
1397
+ try:
1398
+ _typedef_both(Types.TracebackType, refs=_tb_refs)
1399
+ except AttributeError: # missing
1400
+ pass
1401
+
1402
+ _typedef_both(str, leng=_len_unicode, item=_sizeof_Cunicode)
1403
+
1404
+ try: # <type 'KeyedRef'>
1405
+ _typedef_both(Weakref.KeyedRef, refs=_weak_refs, heap=True) # plus head
1406
+ except AttributeError: # missing
1407
+ pass
1408
+
1409
+ try: # <type 'weakproxy'>
1410
+ _typedef_both(Weakref.ProxyType)
1411
+ except AttributeError: # missing
1412
+ pass
1413
+
1414
+ try: # <type 'weakref'>
1415
+ _typedef_both(Weakref.ReferenceType, refs=_weak_refs)
1416
+ except AttributeError: # missing
1417
+ pass
1418
+
1419
+ # some other, callable types
1420
+ _typedef_code(object, kind=_kind_ignored)
1421
+ _typedef_code(super, kind=_kind_ignored)
1422
+ _typedef_code(_Type_type, kind=_kind_ignored)
1423
+
1424
+ try:
1425
+ _typedef_code(classmethod, refs=_im_refs)
1426
+ except NameError:
1427
+ pass
1428
+ try:
1429
+ _typedef_code(staticmethod, refs=_im_refs)
1430
+ except NameError:
1431
+ pass
1432
+ try:
1433
+ _typedef_code(Types.MethodType, refs=_im_refs)
1434
+ except NameError:
1435
+ pass
1436
+
1437
+ try: # generator (expression), no itemsize, no len(), not callable()
1438
+ _typedef_both(Types.GeneratorType, refs=_gen_refs)
1439
+ except AttributeError: # missing
1440
+ pass
1441
+
1442
+ try: # <type 'weakcallableproxy'>
1443
+ _typedef_code(Weakref.CallableProxyType, refs=_weak_refs)
1444
+ except AttributeError: # missing
1445
+ pass
1446
+
1447
+ # any type-specific iterators
1448
+ s = [_items({}), _keys({}), _values({})]
1449
+ try: # reversed list and tuples iterators
1450
+ s.extend([reversed([]), reversed(())])
1451
+ except NameError: # missing
1452
+ pass
1453
+
1454
+ try: # callable-iterator
1455
+ from re import finditer
1456
+ s.append(finditer(_NN, _NN))
1457
+ del finditer
1458
+ except ImportError: # missing
1459
+ pass
1460
+
1461
+ for t in _values(_typedefs):
1462
+ if t.type and t.leng:
1463
+ try: # create an (empty) instance
1464
+ s.append(t.type())
1465
+ except TypeError:
1466
+ pass
1467
+ for t in s:
1468
+ try:
1469
+ i = iter(t)
1470
+ _typedef_both(type(i), leng=_len_iter, refs=_iter_refs, item=0) # no itemsize!
1471
+ except (KeyError, TypeError): # ignore non-iterables, duplicates, etc.
1472
+ pass
1473
+ del i, s, t
1474
+
1475
+
1476
+ def _typedef(obj, derive=False, frames=False, infer=False): # MCCABE 25
1477
+ '''Create a new typedef for an object.
1478
+ '''
1479
+ t = type(obj)
1480
+ v = _Typedef(base=_basicsize(t, obj=obj),
1481
+ kind=_kind_dynamic, type=t)
1482
+ # _printf('new %r %r/%r %s', t, _basicsize(t), _itemsize(t), _repr(dir(obj)))
1483
+ if ismodule(obj): # handle module like dict
1484
+ v.dup(item=_dict_typedef.item + _sizeof_CPyModuleObject,
1485
+ leng=_len_module,
1486
+ refs=_module_refs)
1487
+ elif _isframe(obj):
1488
+ v.set(base=_basicsize(t, base=_sizeof_CPyFrameObject, obj=obj),
1489
+ item=_itemsize(t),
1490
+ leng=_len_frame,
1491
+ refs=_frame_refs)
1492
+ if not frames: # ignore frames
1493
+ v.set(kind=_kind_ignored)
1494
+ elif iscode(obj):
1495
+ v.set(base=_basicsize(t, base=_sizeof_CPyCodeObject, obj=obj),
1496
+ item=_sizeof_Cvoidp,
1497
+ leng=_len_code,
1498
+ refs=_co_refs,
1499
+ both=False) # code only
1500
+ elif callable(obj):
1501
+ if isclass(obj): # class or type
1502
+ v.set(refs=_class_refs,
1503
+ both=False) # code only
1504
+ if _isignored(obj):
1505
+ v.set(kind=_kind_ignored)
1506
+ elif isbuiltin(obj): # function or method
1507
+ v.set(both=False, # code only
1508
+ kind=_kind_ignored)
1509
+ elif isfunction(obj):
1510
+ v.set(refs=_func_refs,
1511
+ both=False) # code only
1512
+ elif ismethod(obj):
1513
+ v.set(refs=_im_refs,
1514
+ both=False) # code only
1515
+ elif isclass(t): # callable instance, e.g. SCons,
1516
+ # handle like any other instance further below
1517
+ v.set(item=_itemsize(t), safe_len=True,
1518
+ refs=_inst_refs) # not code only!
1519
+ else:
1520
+ v.set(both=False) # code only
1521
+ elif _issubclass(t, dict):
1522
+ v.dup(kind=_kind_derived)
1523
+ elif _isdictype(obj) or (infer and _infer_dict(obj)):
1524
+ v.dup(kind=_kind_inferred)
1525
+ elif _iscell(obj):
1526
+ v.set(item=_itemsize(t), refs=_cell_refs)
1527
+ elif _isnamedtuple(obj):
1528
+ v.set(refs=_namedtuple_refs)
1529
+ elif _numpy and _isnumpy(obj):
1530
+ v.set(**_numpy_kwds(obj))
1531
+ elif isinstance(obj, _array):
1532
+ v.set(**_array_kwds(obj))
1533
+ elif _isignored(obj):
1534
+ v.set(kind=_kind_ignored)
1535
+ else: # assume an instance of some class
1536
+ if derive:
1537
+ p = _derive_typedef(t)
1538
+ if p: # duplicate parent
1539
+ v.dup(other=p, kind=_kind_derived)
1540
+ return v
1541
+ if _issubclass(t, Exception):
1542
+ v.set(item=_itemsize(t), safe_len=True,
1543
+ refs=_exc_refs,
1544
+ kind=_kind_derived)
1545
+ elif isinstance(obj, Exception):
1546
+ v.set(item=_itemsize(t), safe_len=True,
1547
+ refs=_exc_refs)
1548
+ else:
1549
+ v.set(item=_itemsize(t), safe_len=True,
1550
+ refs=_inst_refs)
1551
+ return v
1552
+
1553
+
1554
+ class _Prof(object):
1555
+ '''Internal type profile class.
1556
+ '''
1557
+ high = 0 # largest size
1558
+ number = 0 # number of (unique) objects
1559
+ objref = None # largest obj (weakref)
1560
+ total = 0 # total size
1561
+ weak = False # objref is weakref(obj)
1562
+
1563
+ def __cmp__(self, other):
1564
+ if self.total < other.total:
1565
+ return -1
1566
+ elif self.total > other.total:
1567
+ return +1
1568
+ elif self.number < other.number:
1569
+ return -1
1570
+ elif self.number > other.number:
1571
+ return +1
1572
+ return 0
1573
+
1574
+ def __lt__(self, other): # for Python 3+
1575
+ return self.__cmp__(other) < 0
1576
+
1577
+ def format(self, clip=0, grand=None):
1578
+ '''Return format dict.
1579
+ '''
1580
+ if self.number > 1: # avg., plural
1581
+ a, p = int(self.total / self.number), 's'
1582
+ else:
1583
+ a, p = self.total, _NN
1584
+ o = self.objref
1585
+ if self.weak:
1586
+ o = o()
1587
+ t = _SI2(self.total)
1588
+ if grand:
1589
+ t += ' (%s)' % _p100(self.total, grand, prec=0)
1590
+ return dict(avg=_SI2(a), high=_SI2(self.high),
1591
+ lengstr=_lengstr(o), obj=_repr(o, clip=clip),
1592
+ plural=p, total=t)
1593
+
1594
+ def update(self, obj, size):
1595
+ '''Update this profile.
1596
+ '''
1597
+ self.number += 1
1598
+ self.total += size
1599
+ if self.high < size: # largest
1600
+ self.high = size
1601
+ try: # prefer using weak ref
1602
+ self.objref, self.weak = Weakref.ref(obj), True
1603
+ except TypeError:
1604
+ self.objref, self.weak = obj, False
1605
+
1606
+
1607
+ class _Rank(object):
1608
+ '''Internal largest object class.
1609
+ '''
1610
+ deep = 0 # recursion depth
1611
+ id = 0 # id(obj)
1612
+ key = None # Typedef
1613
+ objref = None # obj or Weakref.ref(obj)
1614
+ pid = 0 # id(parent obj)
1615
+ size = 0 # size in bytes
1616
+ weak = False # objref is Weakref.ref
1617
+
1618
+ def __init__(self, key, obj, size, deep, pid):
1619
+ self.deep = deep
1620
+ self.id = id(obj)
1621
+ self.key = key
1622
+ try: # prefer using weak ref
1623
+ self.objref, self.weak = Weakref.ref(obj), True
1624
+ except TypeError:
1625
+ self.objref, self.weak = obj, False
1626
+ self.pid = pid
1627
+ self.size = size
1628
+
1629
+ def format(self, clip=0, id2x={}):
1630
+ '''Return this *rank* as string.
1631
+ '''
1632
+ def _ix(_id): # id or parent_id
1633
+ return id2x.get(_id, '?')
1634
+
1635
+ o = self.objref() if self.weak else self.objref
1636
+ d = (' (at %s)' % (self.deep,)) if self.deep > 0 else _NN
1637
+ p = (', pix %s' % (_ix(self.pid),)) if self.pid else _NN
1638
+ return '%s: %s%s, ix %s%s%s' % (_prepr(self.key, clip=clip),
1639
+ _repr(o, clip=clip), _lengstr(o), _ix(self.id), d, p)
1640
+
1641
+
1642
+ class _Seen(dict):
1643
+ '''Internal obj visits counter.
1644
+ '''
1645
+ def again(self, key):
1646
+ try:
1647
+ s = self[key] + 1
1648
+ except KeyError:
1649
+ s = 1
1650
+ if s > 0:
1651
+ self[key] = s
1652
+
1653
+
1654
+ # Public classes
1655
+
1656
+ class Asized(object):
1657
+ '''Stores the results of an **asized** object in the following
1658
+ 4 attributes:
1659
+
1660
+ *size* -- total size of the object (including referents)
1661
+
1662
+ *flat* -- flat size of the object (in bytes)
1663
+
1664
+ *name* -- name or ``repr`` of the object
1665
+
1666
+ *refs* -- tuple containing an **Asized** instance for each referent
1667
+ '''
1668
+ __slots__ = ('flat', 'name', 'refs', 'size')
1669
+
1670
+ def __init__(self, size, flat, refs=(), name=None):
1671
+ self.size = size # total size
1672
+ self.flat = flat # flat size
1673
+ self.name = name # name, repr or None
1674
+ self.refs = tuple(refs)
1675
+
1676
+ def __str__(self):
1677
+ return 'size %r, flat %r, refs[%d], name %r' % (
1678
+ self.size, self.flat, len(self.refs), self.name)
1679
+
1680
+ def format(self, format='%(name)s size=%(size)d flat=%(flat)d',
1681
+ depth=-1, order_by='size', indent=_NN):
1682
+ '''Format the size information of the object and of all
1683
+ sized referents as a string.
1684
+
1685
+ *format* -- Specifies the format per instance (with 'name',
1686
+ 'size' and 'flat' as interpolation parameters)
1687
+
1688
+ *depth* -- Recursion level up to which the referents are
1689
+ printed (use -1 for unlimited)
1690
+
1691
+ *order_by* -- Control sort order of referents, valid choices
1692
+ are 'name', 'size' and 'flat'
1693
+
1694
+ *indent* -- Optional indentation (default '')
1695
+ '''
1696
+ t = indent + (format % dict(size=self.size, flat=self.flat,
1697
+ name=self.name))
1698
+ if depth and self.refs:
1699
+ rs = sorted(self.refs, key=lambda x: getattr(x, order_by),
1700
+ reverse=order_by in ('size', 'flat'))
1701
+ rs = [r.format(format=format, depth=depth-1, order_by=order_by,
1702
+ indent=indent+' ') for r in rs]
1703
+ t = '\n'.join([t] + rs)
1704
+ return t
1705
+
1706
+ def get(self, name, dflt=None):
1707
+ '''Return the named referent (or *dflt* if not found).
1708
+ '''
1709
+ for ref in self.refs:
1710
+ if name == ref.name:
1711
+ return ref
1712
+ return dflt
1713
+
1714
+
1715
+ class Asizer(object):
1716
+ '''Sizer state and options to accumulate sizes.
1717
+ '''
1718
+ _above_ = 1024 # rank only objs of size 1K+
1719
+ _align_ = 8 # alignment, power-of-2
1720
+ _clip_ = 80
1721
+ _code_ = False
1722
+ _cutoff_ = 0 # in percent
1723
+ _derive_ = False
1724
+ _detail_ = 0 # for Asized only
1725
+ _frames_ = False
1726
+ _infer_ = False
1727
+ _limit_ = 100
1728
+ _stats_ = 0
1729
+
1730
+ _depth = 0 # deepest recursion
1731
+ _excl_d = None # {}
1732
+ _ign_d = _kind_ignored
1733
+ _incl = _NN # or ' (incl. code)'
1734
+ _mask = 7 # see _align_
1735
+ _missed = 0 # due to errors
1736
+ _profile = False # no profiling
1737
+ _profs = None # {}
1738
+ _ranked = 0
1739
+ _ranks = [] # type: List[_Rank] # sorted by decreasing size
1740
+ _seen = None # {}
1741
+ _stream = None # I/O stream for printing
1742
+ _total = 0 # total size
1743
+
1744
+ def __init__(self, **opts):
1745
+ '''New **Asizer** accumulator.
1746
+
1747
+ See this module documentation for more details.
1748
+ See method **reset** for all available options and defaults.
1749
+ '''
1750
+ self._excl_d = {}
1751
+ self.reset(**opts)
1752
+
1753
+ def _c100(self, stats):
1754
+ '''Cutoff as percentage (for backward compatibility)
1755
+ '''
1756
+ s = int(stats)
1757
+ c = int((stats - s) * 100.0 + 0.5) or self.cutoff
1758
+ return s, c
1759
+
1760
+ def _clear(self):
1761
+ '''Clear state.
1762
+ '''
1763
+ self._depth = 0 # recursion depth reached
1764
+ self._incl = _NN # or ' (incl. code)'
1765
+ self._missed = 0 # due to errors
1766
+ self._profile = False
1767
+ self._profs = {}
1768
+ self._ranked = 0
1769
+ self._ranks = []
1770
+ self._seen = _Seen()
1771
+ self._total = 0 # total size
1772
+ for k in _keys(self._excl_d):
1773
+ self._excl_d[k] = 0
1774
+ # don't size, profile or rank private, possibly large objs
1775
+ m = sys.modules[__name__]
1776
+ self.exclude_objs(self, self._excl_d, self._profs, self._ranks,
1777
+ self._seen, m, m.__dict__, m.__doc__,
1778
+ _typedefs)
1779
+
1780
+ def _nameof(self, obj):
1781
+ '''Return the object's name.
1782
+ '''
1783
+ return _nameof(obj, _NN) or self._repr(obj)
1784
+
1785
+ def _prepr(self, obj):
1786
+ '''Like **prepr()**.
1787
+ '''
1788
+ return _prepr(obj, clip=self._clip_)
1789
+
1790
+ def _printf(self, fmt, *args, **print3options):
1791
+ '''Print to sys.stdout or the configured stream if any is
1792
+ specified and if the file keyword argument is not already
1793
+ set in the **print3options** for this specific call.
1794
+ '''
1795
+ if self._stream and not print3options.get('file', None):
1796
+ if args:
1797
+ fmt = fmt % args
1798
+ _printf(fmt, file=self._stream, **print3options)
1799
+ else:
1800
+ _printf(fmt, *args, **print3options)
1801
+
1802
+ def _prof(self, key):
1803
+ '''Get _Prof object.
1804
+ '''
1805
+ p = self._profs.get(key, None)
1806
+ if not p:
1807
+ self._profs[key] = p = _Prof()
1808
+ self.exclude_objs(p) # XXX superfluous?
1809
+ return p
1810
+
1811
+ def _rank(self, key, obj, size, deep, pid):
1812
+ '''Rank 100 largest objects by size.
1813
+ '''
1814
+ rs = self._ranks
1815
+ # bisect, see <http://GitHub.com/python/cpython/blob/master/Lib/bisect.py>
1816
+ i, j = 0, len(rs)
1817
+ while i < j:
1818
+ m = (i + j) // 2
1819
+ if size < rs[m].size:
1820
+ i = m + 1
1821
+ else:
1822
+ j = m
1823
+ if i < 100:
1824
+ r = _Rank(key, obj, size, deep, pid)
1825
+ rs.insert(i, r)
1826
+ self.exclude_objs(r) # XXX superfluous?
1827
+ while len(rs) > 100:
1828
+ rs.pop()
1829
+ # self._ranks[:] = rs[:100]
1830
+ self._ranked += 1
1831
+
1832
+ def _repr(self, obj):
1833
+ '''Like ``repr()``.
1834
+ '''
1835
+ return _repr(obj, clip=self._clip_)
1836
+
1837
+ def _sizer(self, obj, pid, deep, sized): # MCCABE 19
1838
+ '''Size an object, recursively.
1839
+ '''
1840
+ s, f, i = 0, 0, id(obj)
1841
+ if i not in self._seen:
1842
+ self._seen[i] = 1
1843
+ elif deep or self._seen[i]:
1844
+ # skip obj if seen before
1845
+ # or if ref of a given obj
1846
+ if self._seen[i]:
1847
+ self._seen.again(i)
1848
+ if sized:
1849
+ s = sized(s, f, name=self._nameof(obj))
1850
+ self.exclude_objs(s)
1851
+ return s # zero
1852
+ else: # deep == seen[i] == 0
1853
+ self._seen.again(i)
1854
+ try:
1855
+ k, rs = _objkey(obj), []
1856
+ if k in self._excl_d:
1857
+ self._excl_d[k] += 1
1858
+ else:
1859
+ v = _typedefs.get(k, None)
1860
+ if not v: # new typedef
1861
+ _typedefs[k] = v = _typedef(obj, derive=self._derive_,
1862
+ frames=self._frames_,
1863
+ infer=self._infer_)
1864
+ if (v.both or self._code_) and v.kind is not self._ign_d:
1865
+ s = f = v.flat(obj, self._mask) # flat size
1866
+ if self._profile:
1867
+ # profile based on *flat* size
1868
+ self._prof(k).update(obj, s)
1869
+ # recurse, but not for nested modules
1870
+ if v.refs and deep < self._limit_ \
1871
+ and not (deep and ismodule(obj)):
1872
+ # add sizes of referents
1873
+ z, d = self._sizer, deep + 1
1874
+ if sized and deep < self._detail_:
1875
+ # use named referents
1876
+ self.exclude_objs(rs)
1877
+ for o in v.refs(obj, True):
1878
+ if isinstance(o, _NamedRef):
1879
+ r = z(o.ref, i, d, sized)
1880
+ r.name = o.name
1881
+ else:
1882
+ r = z(o, i, d, sized)
1883
+ r.name = self._nameof(o)
1884
+ rs.append(r)
1885
+ s += r.size
1886
+ else: # just size and accumulate
1887
+ for o in v.refs(obj, False):
1888
+ s += z(o, i, d, None)
1889
+ # deepest recursion reached
1890
+ if self._depth < d:
1891
+ self._depth = d
1892
+ if self._stats_ and s > self._above_ > 0:
1893
+ # rank based on *total* size
1894
+ self._rank(k, obj, s, deep, pid)
1895
+ except RuntimeError: # XXX RecursionLimitExceeded:
1896
+ self._missed += 1
1897
+ if not deep:
1898
+ self._total += s # accumulate
1899
+ if sized:
1900
+ s = sized(s, f, name=self._nameof(obj), refs=rs)
1901
+ self.exclude_objs(s)
1902
+ return s
1903
+
1904
+ def _sizes(self, objs, sized=None):
1905
+ '''Return the size or an **Asized** instance for each
1906
+ given object plus the total size. The total includes
1907
+ the size of duplicates only once.
1908
+ '''
1909
+ self.exclude_refs(*objs) # skip refs to objs
1910
+ s, t = {}, []
1911
+ self.exclude_objs(s, t)
1912
+ for o in objs:
1913
+ i = id(o)
1914
+ if i in s: # duplicate
1915
+ self._seen.again(i)
1916
+ else:
1917
+ s[i] = self._sizer(o, 0, 0, sized)
1918
+ t.append(s[i])
1919
+ return tuple(t)
1920
+
1921
+ @property
1922
+ def above(self):
1923
+ '''Get the large object size threshold (int).
1924
+ '''
1925
+ return self._above_
1926
+
1927
+ @property
1928
+ def align(self):
1929
+ '''Get the size alignment (int).
1930
+ '''
1931
+ return self._align_
1932
+
1933
+ def asized(self, *objs, **opts):
1934
+ '''Size each object and return an **Asized** instance with
1935
+ size information and referents up to the given detail
1936
+ level (and with modified options, see method **set**).
1937
+
1938
+ If only one object is given, the return value is the
1939
+ **Asized** instance for that object. The **Asized** size
1940
+ of duplicate and ignored objects will be zero.
1941
+ '''
1942
+ if opts:
1943
+ self.set(**opts)
1944
+ t = self._sizes(objs, Asized)
1945
+ return t[0] if len(t) == 1 else t
1946
+
1947
+ def asizeof(self, *objs, **opts):
1948
+ '''Return the combined size of the given objects
1949
+ (with modified options, see method **set**).
1950
+ '''
1951
+ if opts:
1952
+ self.set(**opts)
1953
+ self.exclude_refs(*objs) # skip refs to objs
1954
+ return sum(self._sizer(o, 0, 0, None) for o in objs)
1955
+
1956
+ def asizesof(self, *objs, **opts):
1957
+ '''Return the individual sizes of the given objects
1958
+ (with modified options, see method **set**).
1959
+
1960
+ The size of duplicate and ignored objects will be zero.
1961
+ '''
1962
+ if opts:
1963
+ self.set(**opts)
1964
+ return self._sizes(objs, None)
1965
+
1966
+ @property
1967
+ def clip(self):
1968
+ '''Get the clipped string length (int).
1969
+ '''
1970
+ return self._clip_
1971
+
1972
+ @property
1973
+ def code(self):
1974
+ '''Size (byte) code (bool).
1975
+ '''
1976
+ return self._code_
1977
+
1978
+ @property
1979
+ def cutoff(self):
1980
+ '''Stats cutoff (int).
1981
+ '''
1982
+ return self._cutoff_
1983
+
1984
+ @property
1985
+ def derive(self):
1986
+ '''Derive types (bool).
1987
+ '''
1988
+ return self._derive_
1989
+
1990
+ @property
1991
+ def detail(self):
1992
+ '''Get the detail level for **Asized** refs (int).
1993
+ '''
1994
+ return self._detail_
1995
+
1996
+ @property
1997
+ def duplicate(self):
1998
+ '''Get the number of duplicate objects seen so far (int).
1999
+ '''
2000
+ return sum(1 for v in _values(self._seen) if v > 1) # == len
2001
+
2002
+ def exclude_objs(self, *objs):
2003
+ '''Exclude the specified objects from sizing, profiling and ranking.
2004
+ '''
2005
+ for o in objs:
2006
+ self._seen.setdefault(id(o), -1)
2007
+
2008
+ def exclude_refs(self, *objs):
2009
+ '''Exclude any references to the specified objects from sizing.
2010
+
2011
+ While any references to the given objects are excluded, the
2012
+ objects will be sized if specified as positional arguments
2013
+ in subsequent calls to methods **asizeof** and **asizesof**.
2014
+ '''
2015
+ for o in objs:
2016
+ self._seen.setdefault(id(o), 0)
2017
+
2018
+ def exclude_types(self, *objs):
2019
+ '''Exclude the specified object instances and types from sizing.
2020
+
2021
+ All instances and types of the given objects are excluded,
2022
+ even objects specified as positional arguments in subsequent
2023
+ calls to methods **asizeof** and **asizesof**.
2024
+ '''
2025
+ for o in objs:
2026
+ for t in _key2tuple(o):
2027
+ if t and t not in self._excl_d:
2028
+ self._excl_d[t] = 0
2029
+
2030
+ @property
2031
+ def excluded(self):
2032
+ '''Get the types being excluded (tuple).
2033
+ '''
2034
+ return tuple(_keys(self._excl_d))
2035
+
2036
+ @property
2037
+ def frames(self):
2038
+ '''Ignore stack frames (bool).
2039
+ '''
2040
+ return self._frames_
2041
+
2042
+ @property
2043
+ def ignored(self):
2044
+ '''Ignore certain types (bool).
2045
+ '''
2046
+ return True if self._ign_d else False
2047
+
2048
+ @property
2049
+ def infer(self):
2050
+ '''Infer types (bool).
2051
+ '''
2052
+ return self._infer_
2053
+
2054
+ @property
2055
+ def limit(self):
2056
+ '''Get the recursion limit (int).
2057
+ '''
2058
+ return self._limit_
2059
+
2060
+ @property
2061
+ def missed(self):
2062
+ '''Get the number of objects missed due to errors (int).
2063
+ '''
2064
+ return self._missed
2065
+
2066
+ def print_largest(self, w=0, cutoff=0, **print3options):
2067
+ '''Print the largest objects.
2068
+
2069
+ The available options and defaults are:
2070
+
2071
+ *w=0* -- indentation for each line
2072
+
2073
+ *cutoff=100* -- number of largest objects to print
2074
+
2075
+ *print3options* -- some keyword arguments, like Python 3+ print
2076
+ '''
2077
+ c = int(cutoff) if cutoff else self._cutoff_
2078
+ n = min(len(self._ranks), max(c, 0))
2079
+ s = self._above_
2080
+ if n > 0 and s > 0:
2081
+ self._printf('%s%*d largest object%s (of %d over %d bytes%s)', linesep,
2082
+ w, n, _plural(n), self._ranked, s, _SI(s), **print3options)
2083
+ id2x = dict((r.id, i) for i, r in enumerate(self._ranks))
2084
+ for r in self._ranks[:n]:
2085
+ s, t = r.size, r.format(self._clip_, id2x)
2086
+ self._printf('%*d bytes%s: %s', w, s, _SI(s), t, **print3options)
2087
+
2088
+ def print_profiles(self, w=0, cutoff=0, **print3options):
2089
+ '''Print the profiles above *cutoff* percentage.
2090
+
2091
+ The available options and defaults are:
2092
+
2093
+ *w=0* -- indentation for each line
2094
+
2095
+ *cutoff=0* -- minimum percentage printed
2096
+
2097
+ *print3options* -- some keyword arguments, like Python 3+ print
2098
+ '''
2099
+ # get the profiles with non-zero size or count
2100
+ t = [(v, k) for k, v in _items(self._profs) if v.total > 0 or v.number > 1]
2101
+ if (len(self._profs) - len(t)) < 9: # just show all
2102
+ t = [(v, k) for k, v in _items(self._profs)]
2103
+ if t:
2104
+ s = _NN
2105
+ if self._total:
2106
+ s = ' (% of grand total)'
2107
+ c = int(cutoff) if cutoff else self._cutoff_
2108
+ C = int(c * 0.01 * self._total)
2109
+ else:
2110
+ C = c = 0
2111
+ self._printf('%s%*d profile%s: total%s, average, and largest flat size%s: largest object',
2112
+ linesep, w, len(t), _plural(len(t)), s, self._incl, **print3options)
2113
+ r = len(t)
2114
+ t = [(v, self._prepr(k)) for v, k in t] # replace types with str for Python 3.11+
2115
+ for v, k in sorted(t, reverse=True):
2116
+ s = 'object%(plural)s: %(total)s, %(avg)s, %(high)s: %(obj)s%(lengstr)s' % v.format(self._clip_, self._total)
2117
+ self._printf('%*d %s %s', w, v.number, k, s, **print3options)
2118
+ r -= 1
2119
+ if r > 1 and v.total < C:
2120
+ self._printf('%+*d profiles below cutoff (%.0f%%)', w, r, c)
2121
+ break
2122
+ z = len(self._profs) - len(t)
2123
+ if z > 0:
2124
+ self._printf('%+*d %r object%s', w, z, 'zero', _plural(z), **print3options)
2125
+
2126
+ def print_stats(self, objs=(), opts={}, sized=(), sizes=(), stats=3, **print3options):
2127
+ '''Prints the statistics.
2128
+
2129
+ The available options and defaults are:
2130
+
2131
+ *w=0* -- indentation for each line
2132
+
2133
+ *objs=()* -- optional, list of objects
2134
+
2135
+ *opts={}* -- optional, dict of options used
2136
+
2137
+ *sized=()* -- optional, tuple of **Asized** instances returned
2138
+
2139
+ *sizes=()* -- optional, tuple of sizes returned
2140
+
2141
+ *stats=3* -- print stats, see function **asizeof**
2142
+
2143
+ *print3options* -- some keyword arguments, like Python 3+ print
2144
+ '''
2145
+ s = min(opts.get('stats', stats) or 0, self.stats)
2146
+ if s > 0: # print stats
2147
+ w = len(str(self.missed + self.seen + self.total)) + 1
2148
+ t = c = _NN
2149
+ o = _kwdstr(**opts)
2150
+ if o and objs:
2151
+ c = ', '
2152
+ # print header line(s)
2153
+ if sized and objs:
2154
+ n = len(objs)
2155
+ if n > 1:
2156
+ self._printf('%sasized(...%s%s) ...', linesep, c, o, **print3options)
2157
+ for i in range(n): # no enumerate in Python 2.2.3
2158
+ self._printf('%*d: %s', w - 1, i, sized[i], **print3options)
2159
+ else:
2160
+ self._printf('%sasized(%s): %s', linesep, o, sized, **print3options)
2161
+ elif sizes and objs:
2162
+ self._printf('%sasizesof(...%s%s) ...', linesep, c, o, **print3options)
2163
+ for z, o in zip(sizes, objs):
2164
+ self._printf('%*d bytes%s%s: %s', w, z, _SI(z), self._incl, self._repr(o), **print3options)
2165
+ else:
2166
+ if objs:
2167
+ t = self._repr(objs)
2168
+ self._printf('%sasizeof(%s%s%s) ...', linesep, t, c, o, **print3options)
2169
+ # print summary
2170
+ self.print_summary(w=w, objs=objs, **print3options)
2171
+ # for backward compatibility, cutoff from fractional stats
2172
+ s, c = self._c100(s)
2173
+ self.print_largest(w=w, cutoff=c if s < 2 else 10, **print3options)
2174
+ if s > 1: # print profile
2175
+ self.print_profiles(w=w, cutoff=c, **print3options)
2176
+ if s > 2: # print typedefs
2177
+ self.print_typedefs(w=w, **print3options) # PYCHOK .print_largest?
2178
+
2179
+ def print_summary(self, w=0, objs=(), **print3options):
2180
+ '''Print the summary statistics.
2181
+
2182
+ The available options and defaults are:
2183
+
2184
+ *w=0* -- indentation for each line
2185
+
2186
+ *objs=()* -- optional, list of objects
2187
+
2188
+ *print3options* -- some keyword arguments, like Python 3+ print
2189
+ '''
2190
+ self._printf('%*d bytes%s%s', w, self._total, _SI(self._total), self._incl, **print3options)
2191
+ if self._mask:
2192
+ self._printf('%*d byte aligned', w, self._mask + 1, **print3options)
2193
+ self._printf('%*d byte sizeof(void*)', w, _sizeof_Cvoidp, **print3options)
2194
+ n = len(objs or ())
2195
+ self._printf('%*d object%s %s', w, n, _plural(n), 'given', **print3options)
2196
+ n = self.sized
2197
+ self._printf('%*d object%s %s', w, n, _plural(n), 'sized', **print3options)
2198
+ if self._excl_d:
2199
+ n = sum(_values(self._excl_d))
2200
+ self._printf('%*d object%s %s', w, n, _plural(n), 'excluded', **print3options)
2201
+ n = self.seen
2202
+ self._printf('%*d object%s %s', w, n, _plural(n), 'seen', **print3options)
2203
+ n = self.ranked
2204
+ if n > 0:
2205
+ self._printf('%*d object%s %s', w, n, _plural(n), 'ranked', **print3options)
2206
+ n = self.missed
2207
+ self._printf('%*d object%s %s', w, n, _plural(n), 'missed', **print3options)
2208
+ n = self.duplicate
2209
+ self._printf('%*d duplicate%s', w, n, _plural(n), **print3options)
2210
+ if self._depth > 0:
2211
+ self._printf('%*d deepest recursion', w, self._depth, **print3options)
2212
+
2213
+ def print_typedefs(self, w=0, **print3options):
2214
+ '''Print the types and dict tables.
2215
+
2216
+ The available options and defaults are:
2217
+
2218
+ *w=0* -- indentation for each line
2219
+
2220
+ *print3options* -- some keyword arguments, like Python 3+ print
2221
+ '''
2222
+ for k in _all_kinds:
2223
+ # XXX Python 3+ doesn't sort type objects
2224
+ t = [(self._prepr(a), v) for a, v in _items(_typedefs)
2225
+ if v.kind == k and (v.both or self._code_)]
2226
+ if t:
2227
+ self._printf('%s%*d %s type%s: basicsize, itemsize, _len_(), _refs()',
2228
+ linesep, w, len(t), k, _plural(len(t)), **print3options)
2229
+ for a, v in sorted(t):
2230
+ self._printf('%*s %s: %s', w, _NN, a, v, **print3options)
2231
+ # dict and dict-like classes
2232
+ t = sum(len(v) for v in _values(_dict_types))
2233
+ if t:
2234
+ self._printf('%s%*d dict/-like classes:', linesep, w, t, **print3options)
2235
+ for m, v in _items(_dict_types):
2236
+ self._printf('%*s %s: %s', w, _NN, m, self._prepr(v), **print3options)
2237
+
2238
+ @property
2239
+ def ranked(self):
2240
+ '''Get the number objects ranked by size so far (int).
2241
+ '''
2242
+ return self._ranked
2243
+
2244
+ def reset(self, above=1024, align=8, clip=80, code=False, # PYCHOK too many args
2245
+ cutoff=10, derive=False, detail=0, frames=False, ignored=True,
2246
+ infer=False, limit=100, stats=0, stream=None, **extra):
2247
+ '''Reset sizing options, state, etc. to defaults.
2248
+
2249
+ The available options and default values are:
2250
+
2251
+ *above=0* -- threshold for largest objects stats
2252
+
2253
+ *align=8* -- size alignment
2254
+
2255
+ *code=False* -- incl. (byte)code size
2256
+
2257
+ *cutoff=10* -- limit large objects or profiles stats
2258
+
2259
+ *derive=False* -- derive from super type
2260
+
2261
+ *detail=0* -- **Asized** refs level
2262
+
2263
+ *frames=False* -- ignore frame objects
2264
+
2265
+ *ignored=True* -- ignore certain types
2266
+
2267
+ *infer=False* -- try to infer types
2268
+
2269
+ *limit=100* -- recursion limit
2270
+
2271
+ *stats=0* -- print statistics, see function **asizeof**
2272
+
2273
+ *stream=None* -- output stream for printing
2274
+
2275
+ See function **asizeof** for a description of the options.
2276
+ '''
2277
+ if extra:
2278
+ raise _OptionError(self.reset, Error=KeyError, **extra)
2279
+ # options
2280
+ self._above_ = above
2281
+ self._align_ = align
2282
+ self._clip_ = clip
2283
+ self._code_ = code
2284
+ self._cutoff_ = cutoff
2285
+ self._derive_ = derive
2286
+ self._detail_ = detail # for Asized only
2287
+ self._frames_ = frames
2288
+ self._infer_ = infer
2289
+ self._limit_ = limit
2290
+ self._stats_ = stats
2291
+ self._stream = stream
2292
+ if ignored:
2293
+ self._ign_d = _kind_ignored
2294
+ else:
2295
+ self._ign_d = None
2296
+ # clear state
2297
+ self._clear()
2298
+ self.set(align=align, code=code, cutoff=cutoff, stats=stats)
2299
+
2300
+ @property
2301
+ def seen(self):
2302
+ '''Get the number objects seen so far (int).
2303
+ '''
2304
+ return sum(v for v in _values(self._seen) if v > 0)
2305
+
2306
+ def set(self, above=None, align=None, code=None, cutoff=None,
2307
+ frames=None, detail=None, limit=None, stats=None):
2308
+ '''Set some sizing options. See also **reset**.
2309
+
2310
+ The available options are:
2311
+
2312
+ *above* -- threshold for largest objects stats
2313
+
2314
+ *align* -- size alignment
2315
+
2316
+ *code* -- incl. (byte)code size
2317
+
2318
+ *cutoff* -- limit large objects or profiles stats
2319
+
2320
+ *detail* -- **Asized** refs level
2321
+
2322
+ *frames* -- size or ignore frame objects
2323
+
2324
+ *limit* -- recursion limit
2325
+
2326
+ *stats* -- print statistics, see function **asizeof**
2327
+
2328
+ Any options not set remain unchanged from the previous setting.
2329
+ '''
2330
+ # adjust
2331
+ if above is not None:
2332
+ self._above_ = int(above)
2333
+ if align is not None:
2334
+ if align > 1:
2335
+ m = align - 1
2336
+ if m & align:
2337
+ raise _OptionError(self.set, align=align)
2338
+ else:
2339
+ m = 0
2340
+ self._align_ = align
2341
+ self._mask = m
2342
+ if code is not None:
2343
+ self._code_ = code
2344
+ if code: # incl. (byte)code
2345
+ self._incl = ' (incl. code)'
2346
+ if detail is not None:
2347
+ self._detail_ = detail
2348
+ if frames is not None:
2349
+ self._frames_ = frames
2350
+ if limit is not None:
2351
+ self._limit_ = limit
2352
+ if stats is not None:
2353
+ if stats < 0:
2354
+ raise _OptionError(self.set, stats=stats)
2355
+ # for backward compatibility, cutoff from fractional stats
2356
+ s, c = self._c100(stats)
2357
+ self._cutoff_ = int(cutoff) if cutoff else c
2358
+ self._stats_ = s
2359
+ self._profile = s > 1 # profile types
2360
+
2361
+ @property
2362
+ def sized(self):
2363
+ '''Get the number objects sized so far (int).
2364
+ '''
2365
+ return sum(1 for v in _values(self._seen) if v > 0)
2366
+
2367
+ @property
2368
+ def stats(self):
2369
+ '''Get the stats and cutoff setting (float).
2370
+ '''
2371
+ return self._stats_ # + (self._cutoff_ * 0.01)
2372
+
2373
+ @property
2374
+ def total(self):
2375
+ '''Get the total size (in bytes) accumulated so far.
2376
+ '''
2377
+ return self._total
2378
+
2379
+
2380
+ # Public functions
2381
+
2382
+ def adict(*classes):
2383
+ '''Install one or more classes to be handled as dict.
2384
+ '''
2385
+ a = True
2386
+ for c in classes:
2387
+ # if class is dict-like, add class
2388
+ # name to _dict_types[_moduleof(c)]
2389
+ n = _nameof(c)
2390
+ if n and isclass(c) and _infer_dict(c):
2391
+ m = _moduleof(c)
2392
+ t = _dict_types.get(m, ())
2393
+ if n not in t: # extend tuple
2394
+ _dict_types[m] = t + (n,)
2395
+ else: # not a dict-like class
2396
+ a = False
2397
+ return a # all installed if True
2398
+
2399
+
2400
+ def amapped(percentage=None):
2401
+ '''Set/get approximate mapped memory usage as a percentage
2402
+ of the mapped file size.
2403
+
2404
+ Sets the new percentage if not None and returns the
2405
+ previously set percentage.
2406
+
2407
+ Applies only to *numpy.memmap* objects.
2408
+ '''
2409
+ global _amapped
2410
+ p = _amapped * 100.0
2411
+ if percentage is not None:
2412
+ _amapped = max(0, min(1, percentage * 0.01))
2413
+ return p
2414
+
2415
+
2416
+ _amapped = 0.01 # 0 <= percentage <= 1.0
2417
+ _asizer = Asizer()
2418
+
2419
+
2420
+ def asized(*objs, **opts):
2421
+ '''Return a tuple containing an **Asized** instance for each
2422
+ object passed as positional argument.
2423
+
2424
+ The available options and defaults are:
2425
+
2426
+ *above=0* -- threshold for largest objects stats
2427
+
2428
+ *align=8* -- size alignment
2429
+
2430
+ *code=False* -- incl. (byte)code size
2431
+
2432
+ *cutoff=10* -- limit large objects or profiles stats
2433
+
2434
+ *derive=False* -- derive from super type
2435
+
2436
+ *detail=0* -- Asized refs level
2437
+
2438
+ *frames=False* -- ignore stack frame objects
2439
+
2440
+ *ignored=True* -- ignore certain types
2441
+
2442
+ *infer=False* -- try to infer types
2443
+
2444
+ *limit=100* -- recursion limit
2445
+
2446
+ *stats=0* -- print statistics
2447
+
2448
+ If only one object is given, the return value is the **Asized**
2449
+ instance for that object. Otherwise, the length of the returned
2450
+ tuple matches the number of given objects.
2451
+
2452
+ The **Asized** size of duplicate and ignored objects will be zero.
2453
+
2454
+ Set *detail* to the desired referents level and *limit* to the
2455
+ maximum recursion depth.
2456
+
2457
+ See function **asizeof** for descriptions of the other options.
2458
+ '''
2459
+ _asizer.reset(**opts)
2460
+ if objs:
2461
+ t = _asizer.asized(*objs)
2462
+ _asizer.print_stats(objs, opts=opts, sized=t) # show opts as _kwdstr
2463
+ _asizer._clear()
2464
+ else:
2465
+ t = ()
2466
+ return t
2467
+
2468
+
2469
+ def asizeof(*objs, **opts):
2470
+ '''Return the combined size (in bytes) of all objects passed
2471
+ as positional arguments.
2472
+
2473
+ The available options and defaults are:
2474
+
2475
+ *above=0* -- threshold for largest objects stats
2476
+
2477
+ *align=8* -- size alignment
2478
+
2479
+ *clip=80* -- clip ``repr()`` strings
2480
+
2481
+ *code=False* -- incl. (byte)code size
2482
+
2483
+ *cutoff=10* -- limit large objects or profiles stats
2484
+
2485
+ *derive=False* -- derive from super type
2486
+
2487
+ *frames=False* -- ignore stack frame objects
2488
+
2489
+ *ignored=True* -- ignore certain types
2490
+
2491
+ *infer=False* -- try to infer types
2492
+
2493
+ *limit=100* -- recursion limit
2494
+
2495
+ *stats=0* -- print statistics
2496
+
2497
+ Set *align* to a power of 2 to align sizes. Any value less
2498
+ than 2 avoids size alignment.
2499
+
2500
+ If *all* is True and if no positional arguments are supplied.
2501
+ size all current gc objects, including module, global and stack
2502
+ frame objects.
2503
+
2504
+ A positive *clip* value truncates all repr() strings to at
2505
+ most *clip* characters.
2506
+
2507
+ The (byte)code size of callable objects like functions,
2508
+ methods, classes, etc. is included only if *code* is True.
2509
+
2510
+ If *derive* is True, new types are handled like an existing
2511
+ (super) type provided there is one and only of those.
2512
+
2513
+ By default certain base types like object, super, etc. are
2514
+ ignored. Set *ignored* to False to include those.
2515
+
2516
+ If *infer* is True, new types are inferred from attributes
2517
+ (only implemented for dict types on callable attributes
2518
+ as get, has_key, items, keys and values).
2519
+
2520
+ Set *limit* to a positive value to accumulate the sizes of
2521
+ the referents of each object, recursively up to the limit.
2522
+ Using *limit=0* returns the sum of the flat sizes of the
2523
+ given objects. High *limit* values may cause runtime errors
2524
+ and miss objects for sizing.
2525
+
2526
+ A positive value for *stats* prints up to 9 statistics, (1)
2527
+ a summary of the number of objects sized and seen and a list
2528
+ of the largests objects with size over *above* bytes, (2) a
2529
+ simple profile of the sized objects by type and (3+) up to 6
2530
+ tables showing the static, dynamic, derived, ignored, inferred
2531
+ and dict types used, found respectively installed.
2532
+ The fractional part of the *stats* value (x 100) is the number
2533
+ of largest objects shown for (*stats*1.+) or the cutoff
2534
+ percentage for simple profiles for (*stats*=2.+). For example,
2535
+ *stats=1.10* shows the summary and the 10 largest objects,
2536
+ also the default.
2537
+
2538
+ See this module documentation for the definition of flat size.
2539
+ '''
2540
+ t, p, x = _objs_opts_x(asizeof, objs, **opts)
2541
+ _asizer.reset(**p)
2542
+ if t:
2543
+ if x: # don't size, profile or rank _getobjects tuple
2544
+ _asizer.exclude_objs(t)
2545
+ s = _asizer.asizeof(*t)
2546
+ _asizer.print_stats(objs=t, opts=opts) # show opts as _kwdstr
2547
+ _asizer._clear()
2548
+ else:
2549
+ s = 0
2550
+ return s
2551
+
2552
+
2553
+ def asizesof(*objs, **opts):
2554
+ '''Return a tuple containing the size (in bytes) of all objects
2555
+ passed as positional arguments.
2556
+
2557
+ The available options and defaults are:
2558
+
2559
+ *above=1024* -- threshold for largest objects stats
2560
+
2561
+ *align=8* -- size alignment
2562
+
2563
+ *clip=80* -- clip ``repr()`` strings
2564
+
2565
+ *code=False* -- incl. (byte)code size
2566
+
2567
+ *cutoff=10* -- limit large objects or profiles stats
2568
+
2569
+ *derive=False* -- derive from super type
2570
+
2571
+ *frames=False* -- ignore stack frame objects
2572
+
2573
+ *ignored=True* -- ignore certain types
2574
+
2575
+ *infer=False* -- try to infer types
2576
+
2577
+ *limit=100* -- recursion limit
2578
+
2579
+ *stats=0* -- print statistics
2580
+
2581
+ See function **asizeof** for a description of the options.
2582
+
2583
+ The length of the returned tuple equals the number of given
2584
+ objects.
2585
+
2586
+ The size of duplicate and ignored objects will be zero.
2587
+ '''
2588
+ _asizer.reset(**opts)
2589
+ if objs:
2590
+ t = _asizer.asizesof(*objs)
2591
+ _asizer.print_stats(objs, opts=opts, sizes=t) # show opts as _kwdstr
2592
+ _asizer._clear()
2593
+ else:
2594
+ t = ()
2595
+ return t
2596
+
2597
+
2598
+ def _typedefof(obj, save=False, **opts):
2599
+ '''Get the typedef for an object.
2600
+ '''
2601
+ k = _objkey(obj)
2602
+ v = _typedefs.get(k, None)
2603
+ if not v: # new typedef
2604
+ v = _typedef(obj, **opts)
2605
+ if save:
2606
+ _typedefs[k] = v
2607
+ return v
2608
+
2609
+
2610
+ def basicsize(obj, **opts):
2611
+ '''Return the basic size of an object (in bytes).
2612
+
2613
+ The available options and defaults are:
2614
+
2615
+ *derive=False* -- derive type from super type
2616
+
2617
+ *infer=False* -- try to infer types
2618
+
2619
+ *save=False* -- save the object's type definition if new
2620
+
2621
+ See this module documentation for the definition of *basic size*.
2622
+ '''
2623
+ b = t = _typedefof(obj, **opts)
2624
+ if t:
2625
+ b = t.base
2626
+ return b
2627
+
2628
+
2629
+ def flatsize(obj, align=0, **opts):
2630
+ '''Return the flat size of an object (in bytes), optionally aligned
2631
+ to the given power-of-2.
2632
+
2633
+ See function **basicsize** for a description of other available options.
2634
+
2635
+ See this module documentation for the definition of *flat size*.
2636
+ '''
2637
+ f = t = _typedefof(obj, **opts)
2638
+ if t:
2639
+ if align > 1:
2640
+ m = align - 1
2641
+ if m & align:
2642
+ raise _OptionError(flatsize, align=align)
2643
+ else:
2644
+ m = 0
2645
+ f = t.flat(obj, mask=m)
2646
+ return f
2647
+
2648
+
2649
+ def itemsize(obj, **opts):
2650
+ '''Return the item size of an object (in bytes).
2651
+
2652
+ See function **basicsize** for a description of the available options.
2653
+
2654
+ See this module documentation for the definition of *item size*.
2655
+ '''
2656
+ i = t = _typedefof(obj, **opts)
2657
+ if t:
2658
+ i, v = t.item, t.vari
2659
+ if v and i == _sizeof_Cbyte:
2660
+ i = getattr(obj, v, i)
2661
+ return i
2662
+
2663
+
2664
+ def leng(obj, **opts):
2665
+ '''Return the length of an object, in number of *items*.
2666
+
2667
+ See function **basicsize** for a description of the available options.
2668
+ '''
2669
+ n = t = _typedefof(obj, **opts)
2670
+ if t:
2671
+ n = t.leng
2672
+ if n and callable(n):
2673
+ i, v, n = t.item, t.vari, n(obj)
2674
+ if v and i == _sizeof_Cbyte:
2675
+ i = getattr(obj, v, i)
2676
+ if i > _sizeof_Cbyte:
2677
+ n = n // i
2678
+ return n
2679
+
2680
+
2681
+ def named_refs(obj, **opts):
2682
+ '''Return all named **referents** of an object (re-using
2683
+ functionality from **asizeof**).
2684
+
2685
+ Does not return un-named *referents*, e.g. objects in a list.
2686
+
2687
+ See function **basicsize** for a description of the available options.
2688
+ '''
2689
+ rs = []
2690
+ v = _typedefof(obj, **opts)
2691
+ if v:
2692
+ v = v.refs
2693
+ if v and callable(v):
2694
+ for r in v(obj, True):
2695
+ try:
2696
+ rs.append((r.name, r.ref))
2697
+ except AttributeError:
2698
+ pass
2699
+ return rs
2700
+
2701
+
2702
+ def refs(obj, **opts):
2703
+ '''Return (a generator for) specific *referents* of an object.
2704
+
2705
+ See function **basicsize** for a description of the available options.
2706
+ '''
2707
+ v = _typedefof(obj, **opts)
2708
+ if v:
2709
+ v = v.refs
2710
+ if v and callable(v):
2711
+ v = v(obj, False)
2712
+ return v
2713
+
2714
+
2715
+ __all__ = [_nameof(_) for _ in (Asized, Asizer, # classes
2716
+ adict, amapped, asized, asizeof, asizesof,
2717
+ basicsize, flatsize, itemsize, leng, refs)]
2718
+
2719
+ if __name__ == '__main__':
2720
+
2721
+ def _examples(**kwds):
2722
+ '''*_Typedef* and size some examples.
2723
+ '''
2724
+ t = 2**99, _array('B', range(127)), _array('d', range(100))
2725
+ if _numpy:
2726
+ t += (_numpy.arange(0),
2727
+ _numpy.array(range(0)),
2728
+ _numpy.ma.masked_array([]),
2729
+ _numpy.memmap(sys.executable, mode='r'), # dtype=_numpy.uint8
2730
+ _numpy.float64(0),
2731
+ _numpy.ndarray(0),
2732
+ _numpy.uint64(2**63)),
2733
+ try: # .matrix deprecated in numpy 1.19.3
2734
+ t += _numpy.matrix(range(0)),
2735
+ except AttributeError:
2736
+ pass
2737
+ asizesof(*t, **kwds) # sizing creates _Typedefs dynamically
2738
+ return t
2739
+
2740
+ if '-examples' in sys.argv or '-x' in sys.argv:
2741
+ # show some asizeof examples
2742
+ import gc
2743
+ collect = False
2744
+ if '-gc' in sys.argv:
2745
+ collect = True
2746
+ gc.collect()
2747
+
2748
+ t = _examples(above=0, cutoff=0, stats=2)
2749
+ amapped(100) # numpy.memmap'd file size
2750
+ # print summary + 10 largest
2751
+ asizeof(all=True, stats=9, above=1024, frames='-frames' in sys.argv)
2752
+
2753
+ if collect:
2754
+ print('gc.collect() %d' % (gc.collect(),))
2755
+
2756
+ elif '-types' in sys.argv or '-t' in sys.argv:
2757
+ # show static and some dynamic _typedefs
2758
+ t = _examples(stats=0)
2759
+ n = len(_typedefs)
2760
+ w = len(str(n)) * ' '
2761
+ _printf('%s%d type definitions: %s and %s, kind ... %s', linesep,
2762
+ n, 'basic-', 'itemsize (leng)', '-type[def]s')
2763
+ for k, td in sorted((_prepr(k), td) for k, td in _items(_typedefs)):
2764
+ t = '%(base)s and %(item)s%(leng)s, %(kind)s%(code)s' % td.format()
2765
+ _printf('%s %s: %s', w, k, t)
2766
+
2767
+ else: # if '-version' in sys.argv or '-v' in sys.argv
2768
+ import platform
2769
+ t = (',', _numpy.__name__, _numpy.__version__) if _numpy else ()
2770
+ _printf('%s %s (Python %s %s %s%s)', __file__, __version__,
2771
+ sys.version.split()[0],
2772
+ platform.architecture()[0],
2773
+ platform.machine(), ' '.join(t))
2774
+
2775
+ # License from the initial version of this source file follows:
2776
+
2777
+ # --------------------------------------------------------------------
2778
+ # Copyright (c) 2002-2022 -- ProphICy Semiconductor, Inc.
2779
+ # All rights reserved.
2780
+ #
2781
+ # Redistribution and use in source and binary forms, with or without
2782
+ # modification, are permitted provided that the following conditions
2783
+ # are met:
2784
+ #
2785
+ # - Redistributions of source code must retain the above copyright
2786
+ # notice, this list of conditions and the following disclaimer.
2787
+ #
2788
+ # - Redistributions in binary form must reproduce the above copyright
2789
+ # notice, this list of conditions and the following disclaimer in
2790
+ # the documentation and/or other materials provided with the
2791
+ # distribution.
2792
+ #
2793
+ # - Neither the name of ProphICy Semiconductor, Inc. nor the names
2794
+ # of its contributors may be used to endorse or promote products
2795
+ # derived from this software without specific prior written
2796
+ # permission.
2797
+ #
2798
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2799
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2800
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2801
+ # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2802
+ # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2803
+ # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2804
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2805
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2806
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2807
+ # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2808
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
2809
+ # OF THE POSSIBILITY OF SUCH DAMAGE.
2810
+ # --------------------------------------------------------------------