imports-logger 2.0.0__py2.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.
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
from __future__ import print_function
|
|
2
|
+
|
|
3
|
+
# released under the MIT license https://opensource.org/licenses/MIT
|
|
4
|
+
__VERSION__ = "2.0.0"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def setup_logger(log_vsize=False):
|
|
8
|
+
print("===> installing imports_logger_override")
|
|
9
|
+
import os
|
|
10
|
+
import psutil
|
|
11
|
+
|
|
12
|
+
# import pdb
|
|
13
|
+
# import pprint
|
|
14
|
+
# import logging
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
from six.moves import builtins
|
|
18
|
+
|
|
19
|
+
# setup the memory vars
|
|
20
|
+
# the call is different on other versions of psutil.
|
|
21
|
+
# i've seen these 2, hopefully this will work in your case
|
|
22
|
+
_this_process = psutil.Process(os.getpid())
|
|
23
|
+
try:
|
|
24
|
+
_this_process.memory_info()
|
|
25
|
+
_f_memory = _this_process.memory_info
|
|
26
|
+
except:
|
|
27
|
+
_this_process.get_memory_info()
|
|
28
|
+
_f_memory = _this_process.get_memory_info
|
|
29
|
+
GET_MEMORY_R = lambda: _f_memory()[0]
|
|
30
|
+
GET_MEMORY_V = lambda: _f_memory()[1]
|
|
31
|
+
|
|
32
|
+
# set up the dirs
|
|
33
|
+
# we'll lot go `{CWD}/__imports_logger/runs/{VERSION}` in which `VERSION` is 001, 002, etc
|
|
34
|
+
REPORTS_DIR_BASE = os.path.join("__imports_logger", "runs")
|
|
35
|
+
if not os.path.exists(REPORTS_DIR_BASE):
|
|
36
|
+
os.makedirs(REPORTS_DIR_BASE)
|
|
37
|
+
dirs = [
|
|
38
|
+
i
|
|
39
|
+
for i in os.listdir(REPORTS_DIR_BASE)
|
|
40
|
+
if os.path.isdir(os.path.join(REPORTS_DIR_BASE, i))
|
|
41
|
+
]
|
|
42
|
+
max_dirs = len(dirs)
|
|
43
|
+
REPORTS_DIR_RUN = os.path.join(REPORTS_DIR_BASE, "%03d" % max_dirs)
|
|
44
|
+
print("===- Logging to `%s`" % REPORTS_DIR_RUN)
|
|
45
|
+
os.makedirs(REPORTS_DIR_RUN)
|
|
46
|
+
writer_success = open(os.path.join(REPORTS_DIR_RUN, "imports.txt"), "a")
|
|
47
|
+
writer_error = open(os.path.join(REPORTS_DIR_RUN, "errors.txt"), "a")
|
|
48
|
+
|
|
49
|
+
# we need this still
|
|
50
|
+
# PY3 - __import__(name, globals=None, locals=None, fromlist=(), level=0) -> module
|
|
51
|
+
# PY2 - __import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module
|
|
52
|
+
realimport = builtins.__import__
|
|
53
|
+
|
|
54
|
+
# our override
|
|
55
|
+
def imports_logger_override(name, *args, **kwargs):
|
|
56
|
+
_mem_start = GET_MEMORY_R()
|
|
57
|
+
_mem_startv = GET_MEMORY_V()
|
|
58
|
+
_package_name = name
|
|
59
|
+
if len(args) == 4:
|
|
60
|
+
_package_name = "%s.%s" % (name, str(args[2]).replace(",", "|"))
|
|
61
|
+
# use sys._getframe, because the `inspect` module leaves a circular reference that won't clean up (even with an explicit delete)
|
|
62
|
+
_frame = sys._getframe(1)
|
|
63
|
+
try:
|
|
64
|
+
_caller_file = _frame.f_locals["__file__"]
|
|
65
|
+
except:
|
|
66
|
+
_caller_file = "<>"
|
|
67
|
+
try:
|
|
68
|
+
try:
|
|
69
|
+
_imported = realimport(name, *args, **kwargs)
|
|
70
|
+
except (ImportError, AttributeError) as exc:
|
|
71
|
+
raise ImportError(str(exc))
|
|
72
|
+
_mem_finish = GET_MEMORY_R()
|
|
73
|
+
_mem_growth = _mem_finish - _mem_start
|
|
74
|
+
if log_vsize:
|
|
75
|
+
_mem_finishv = GET_MEMORY_V()
|
|
76
|
+
_mem_growthv = _mem_finishv - _mem_startv
|
|
77
|
+
_line = "import|%s,%s,%s,%s,%s,%s,%s,%s\n" % (
|
|
78
|
+
_package_name,
|
|
79
|
+
_caller_file,
|
|
80
|
+
_mem_growth,
|
|
81
|
+
_mem_start,
|
|
82
|
+
_mem_finish,
|
|
83
|
+
_mem_growthv,
|
|
84
|
+
_mem_startv,
|
|
85
|
+
_mem_finishv,
|
|
86
|
+
)
|
|
87
|
+
else:
|
|
88
|
+
_line = "import|%s,%s,%s,%s,%s\n" % (
|
|
89
|
+
_package_name,
|
|
90
|
+
_caller_file,
|
|
91
|
+
_mem_growth,
|
|
92
|
+
_mem_start,
|
|
93
|
+
_mem_finish,
|
|
94
|
+
)
|
|
95
|
+
writer_success.write(_line)
|
|
96
|
+
return _imported
|
|
97
|
+
except Exception as e:
|
|
98
|
+
_message = e.args[0]
|
|
99
|
+
if isinstance(e, ImportError) and _message.startswith("No module named"):
|
|
100
|
+
# print("ImportError: %s | via <%s> in <%s>" % (e, _package_name, _caller_file))
|
|
101
|
+
_mem_finish = GET_MEMORY_R()
|
|
102
|
+
_mem_growth = _mem_finish - _mem_start
|
|
103
|
+
if log_vsize:
|
|
104
|
+
_mem_finishv = GET_MEMORY_V()
|
|
105
|
+
_mem_growthv = _mem_finishv - _mem_startv
|
|
106
|
+
_line = "import|%s,%s,%s,%s,%s,%s,%s,%s\n" % (
|
|
107
|
+
_package_name,
|
|
108
|
+
_caller_file,
|
|
109
|
+
_mem_growth,
|
|
110
|
+
_mem_start,
|
|
111
|
+
_mem_finish,
|
|
112
|
+
_mem_growthv,
|
|
113
|
+
_mem_startv,
|
|
114
|
+
_mem_finishv,
|
|
115
|
+
)
|
|
116
|
+
else:
|
|
117
|
+
_line = "import|%s,%s,%s,%s,%s\n" % (
|
|
118
|
+
_package_name,
|
|
119
|
+
_caller_file,
|
|
120
|
+
_mem_growth,
|
|
121
|
+
_mem_start,
|
|
122
|
+
_mem_finish,
|
|
123
|
+
)
|
|
124
|
+
writer_error.write(_line)
|
|
125
|
+
raise
|
|
126
|
+
finally:
|
|
127
|
+
del _caller_file
|
|
128
|
+
del _frame
|
|
129
|
+
|
|
130
|
+
# install the override
|
|
131
|
+
builtins.__import__ = imports_logger_override
|
|
132
|
+
print("<=== imports_logger_override installed")
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: imports_logger
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Quick tool to log import statements
|
|
5
|
+
Home-page: https://github.com/jvanasco/imports_logger
|
|
6
|
+
Author: Jonathan Vanasco
|
|
7
|
+
Author-email: jvanasco@2xlp.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: import,logging,memory
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
23
|
+
Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE.txt
|
|
26
|
+
Requires-Dist: psutil
|
|
27
|
+
Requires-Dist: six
|
|
28
|
+
Provides-Extra: testing
|
|
29
|
+
Requires-Dist: pytest; extra == "testing"
|
|
30
|
+
Requires-Dist: coverage; extra == "testing"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
Import Logger
|
|
36
|
+
=============
|
|
37
|
+
|
|
38
|
+
This was a terrible, quickly slapped together, package designed as a quick debugging tool.
|
|
39
|
+
|
|
40
|
+
Over the past few years, it has proved to be incredibly useful.
|
|
41
|
+
|
|
42
|
+
## what this does
|
|
43
|
+
|
|
44
|
+
This package is used to override calls to `import`, wrapping every import with
|
|
45
|
+
a call to `psutil` which measures memory.
|
|
46
|
+
|
|
47
|
+
The outputs are written to a versioned file as `csv` compatible text files --
|
|
48
|
+
one for "successful" imports, another for "failures"".
|
|
49
|
+
|
|
50
|
+
The output files are written to an `__imports_logged` directory and stored under
|
|
51
|
+
an incremental `__imports_logged/runs` subfolder.
|
|
52
|
+
|
|
53
|
+
This is rough and can be customized. This should NEVER NEVER NEVER be used on
|
|
54
|
+
production code. This is a quick debugging tool.
|
|
55
|
+
|
|
56
|
+
### DANGER DANGER DANGER
|
|
57
|
+
|
|
58
|
+
DO NOT RUN THIS IN PRODUCTION
|
|
59
|
+
|
|
60
|
+
### DANGER DANGER DANGER
|
|
61
|
+
|
|
62
|
+
SERIOUSLY, DO NOT RUN THIS IN PRODUCTION
|
|
63
|
+
|
|
64
|
+
Why not? This library saves the loaded information in a versioned format - so
|
|
65
|
+
every time you start/restart your applications, more disk space will be consumed.
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## so why would I use this?
|
|
69
|
+
|
|
70
|
+
There are two main use-cases:
|
|
71
|
+
|
|
72
|
+
1. The outputs can be processed and analyzed (even imported to Excel!) to
|
|
73
|
+
determine where the biggest imports are, and what causes them.
|
|
74
|
+
|
|
75
|
+
2. Knowing import errors is useful in two situations: refactoring your own code,
|
|
76
|
+
and finding what libraries are conditionally importing other 3rd party tools.
|
|
77
|
+
|
|
78
|
+
## requirements
|
|
79
|
+
|
|
80
|
+
* `psutil`
|
|
81
|
+
|
|
82
|
+
## usage
|
|
83
|
+
|
|
84
|
+
try running the demo.py script
|
|
85
|
+
|
|
86
|
+
it is just...
|
|
87
|
+
|
|
88
|
+
# at the top of your script
|
|
89
|
+
import imports_logger
|
|
90
|
+
imports_logger.setup_logger()
|
|
91
|
+
|
|
92
|
+
# your code here
|
|
93
|
+
import re
|
|
94
|
+
|
|
95
|
+
# this should have created a folder named `__imports_logged/runs/001`
|
|
96
|
+
|
|
97
|
+
the text in runs 001 should look like
|
|
98
|
+
|
|
99
|
+
import|re.None,demo.py,0,12664832,12664832
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
imports_logger/__init__.py,sha256=kDxKvIaUPOLWmrfkJNLhYbwcmtcl3PHJ8vqG0LVsLsg,4899
|
|
2
|
+
imports_logger-2.0.0.dist-info/licenses/LICENSE.txt,sha256=HGwQg0OCAkR5EPZnIxnj4aFfG2Yen_jn6Dami5OiJOc,1083
|
|
3
|
+
imports_logger-2.0.0.dist-info/METADATA,sha256=7277u6Xja1-_GpkVqOfcAJdvoCg12ZTG-goJIke3J28,3054
|
|
4
|
+
imports_logger-2.0.0.dist-info/WHEEL,sha256=Uvlg2aNlEKdilsyFSJt1QX5me0eEbCjQzR3nZeFkvy4,109
|
|
5
|
+
imports_logger-2.0.0.dist-info/top_level.txt,sha256=uwlADt14EuamFFm-BUe5VSxUjal_gOg1WIMSq4MiITw,15
|
|
6
|
+
imports_logger-2.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
Copyright (c) 2016 Jonathan Vanasco
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
5
|
+
|
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
9
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
imports_logger
|