nano-dev-utils 1.4.0__py3-none-any.whl → 1.4.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.
Potentially problematic release.
This version of nano-dev-utils might be problematic. Click here for more details.
- nano_dev_utils/common.py +47 -17
- nano_dev_utils/file_tree_display.py +38 -28
- nano_dev_utils/timers.py +21 -9
- {nano_dev_utils-1.4.0.dist-info → nano_dev_utils-1.4.1.dist-info}/METADATA +28 -18
- nano_dev_utils-1.4.1.dist-info/RECORD +10 -0
- nano_dev_utils-1.4.0.dist-info/RECORD +0 -10
- {nano_dev_utils-1.4.0.dist-info → nano_dev_utils-1.4.1.dist-info}/WHEEL +0 -0
- {nano_dev_utils-1.4.0.dist-info → nano_dev_utils-1.4.1.dist-info}/licenses/LICENSE +0 -0
nano_dev_utils/common.py
CHANGED
|
@@ -61,7 +61,9 @@ def encode_dict(input_dict: dict) -> bytes:
|
|
|
61
61
|
return b' '.join(str(v).encode() for v in input_dict.values())
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def str2file(
|
|
64
|
+
def str2file(
|
|
65
|
+
content: AnyStr, filepath: str, mode: str = 'w', enc: str = 'utf-8'
|
|
66
|
+
) -> None:
|
|
65
67
|
"""Simply save file directly from any string content.
|
|
66
68
|
|
|
67
69
|
Args:
|
|
@@ -86,32 +88,48 @@ def str2file(content: AnyStr, filepath: str, mode: str = 'w', enc: str = 'utf-8'
|
|
|
86
88
|
|
|
87
89
|
|
|
88
90
|
class PredicateBuilder:
|
|
89
|
-
def build_predicate(
|
|
91
|
+
def build_predicate(
|
|
92
|
+
self, allow: FilterSet, block: FilterSet
|
|
93
|
+
) -> Callable[[str], bool]:
|
|
90
94
|
"""Build a memory-efficient predicate function."""
|
|
91
95
|
compile_patts = self.compile_patts
|
|
92
96
|
|
|
93
97
|
allow_lits, allow_patts = compile_patts(allow)
|
|
94
98
|
block_lits, block_patts = compile_patts(block)
|
|
95
99
|
|
|
96
|
-
flag = (
|
|
97
|
-
|
|
100
|
+
flag = (
|
|
101
|
+
1 if allow_lits or allow_patts else 0,
|
|
102
|
+
1 if block_lits or block_patts else 0,
|
|
103
|
+
)
|
|
98
104
|
|
|
99
105
|
match flag: # (allow, block)
|
|
100
106
|
case (0, 0):
|
|
101
107
|
return lambda name: True
|
|
102
108
|
|
|
103
109
|
case (0, 1):
|
|
104
|
-
return partial(
|
|
105
|
-
|
|
110
|
+
return partial(
|
|
111
|
+
self._match_patt_with_lits,
|
|
112
|
+
name_patts=block_patts,
|
|
113
|
+
name_lits=block_lits,
|
|
114
|
+
negate=True,
|
|
115
|
+
)
|
|
106
116
|
|
|
107
117
|
case (1, 0):
|
|
108
|
-
return partial(
|
|
109
|
-
|
|
118
|
+
return partial(
|
|
119
|
+
self._match_patt_with_lits,
|
|
120
|
+
name_patts=allow_patts,
|
|
121
|
+
name_lits=allow_lits,
|
|
122
|
+
negate=False,
|
|
123
|
+
)
|
|
110
124
|
|
|
111
125
|
case (1, 1):
|
|
112
|
-
return partial(
|
|
113
|
-
|
|
114
|
-
|
|
126
|
+
return partial(
|
|
127
|
+
self._allow_block_predicate,
|
|
128
|
+
allow_lits=allow_lits,
|
|
129
|
+
allow_patts=allow_patts,
|
|
130
|
+
block_lits=block_lits,
|
|
131
|
+
block_patts=block_patts,
|
|
132
|
+
)
|
|
115
133
|
|
|
116
134
|
@staticmethod
|
|
117
135
|
def compile_patts(fs: FilterSet) -> tuple[set[str], list[re.Pattern]]:
|
|
@@ -119,7 +137,7 @@ class PredicateBuilder:
|
|
|
119
137
|
return set(), []
|
|
120
138
|
literals, patterns = set(), []
|
|
121
139
|
for item in fs:
|
|
122
|
-
if
|
|
140
|
+
if '*' in item or '?' in item or '[' in item:
|
|
123
141
|
patterns.append(re.compile(fnmatch.translate(item)))
|
|
124
142
|
else:
|
|
125
143
|
literals.add(item)
|
|
@@ -130,15 +148,27 @@ class PredicateBuilder:
|
|
|
130
148
|
"""Return True if name matches any compiled regex pattern."""
|
|
131
149
|
return any(pat.fullmatch(name) for pat in patterns)
|
|
132
150
|
|
|
133
|
-
def _match_patt_with_lits(
|
|
134
|
-
|
|
151
|
+
def _match_patt_with_lits(
|
|
152
|
+
self,
|
|
153
|
+
name: str,
|
|
154
|
+
*,
|
|
155
|
+
name_lits: set[str],
|
|
156
|
+
name_patts: list[re.Pattern],
|
|
157
|
+
negate: bool = False,
|
|
158
|
+
) -> bool:
|
|
135
159
|
"""Return True if name is in literals or matches any pattern."""
|
|
136
160
|
res = name in name_lits or self._match_patts(name, name_patts)
|
|
137
161
|
return not res if negate else res
|
|
138
162
|
|
|
139
|
-
def _allow_block_predicate(
|
|
140
|
-
|
|
141
|
-
|
|
163
|
+
def _allow_block_predicate(
|
|
164
|
+
self,
|
|
165
|
+
name: str,
|
|
166
|
+
*,
|
|
167
|
+
allow_lits: set[str],
|
|
168
|
+
allow_patts: list[re.Pattern],
|
|
169
|
+
block_lits: set[str],
|
|
170
|
+
block_patts: list[re.Pattern],
|
|
171
|
+
) -> bool:
|
|
142
172
|
"""Return True if name is allowed and not blocked (block takes precedence)."""
|
|
143
173
|
if name in block_lits or self._match_patts(name, block_patts):
|
|
144
174
|
return False
|
|
@@ -3,7 +3,7 @@ import re
|
|
|
3
3
|
|
|
4
4
|
from collections.abc import Generator
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing_extensions import
|
|
6
|
+
from typing_extensions import Callable, Any
|
|
7
7
|
|
|
8
8
|
from .common import str2file, FilterSet, PredicateBuilder
|
|
9
9
|
|
|
@@ -22,22 +22,23 @@ class FileTreeDisplay:
|
|
|
22
22
|
visual representations of directories and files.
|
|
23
23
|
Supports exclusion lists, configurable indentation, and custom prefix styles.
|
|
24
24
|
"""
|
|
25
|
+
|
|
25
26
|
def __init__(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
self,
|
|
28
|
+
root_dir: str | None = None,
|
|
29
|
+
filepath: str | None = None,
|
|
30
|
+
ignore_dirs: FilterSet = None,
|
|
31
|
+
ignore_files: FilterSet = None,
|
|
32
|
+
include_dirs: FilterSet = None,
|
|
33
|
+
include_files: FilterSet = None,
|
|
34
|
+
style: str = ' ',
|
|
35
|
+
indent: int = 2,
|
|
36
|
+
files_first: bool = False,
|
|
37
|
+
sort_key_name: str = 'natural',
|
|
38
|
+
reverse: bool = False,
|
|
39
|
+
custom_sort: Callable[[str], Any] | None = None,
|
|
40
|
+
save2file: bool = True,
|
|
41
|
+
printout: bool = False,
|
|
41
42
|
) -> None:
|
|
42
43
|
"""Initialize the FileTreeDisplay instance.
|
|
43
44
|
|
|
@@ -82,7 +83,9 @@ class FileTreeDisplay:
|
|
|
82
83
|
|
|
83
84
|
self.pb = PredicateBuilder()
|
|
84
85
|
self.dir_filter = self.pb.build_predicate(self.include_dirs, self.ignore_dirs)
|
|
85
|
-
self.file_filter = self.pb.build_predicate(
|
|
86
|
+
self.file_filter = self.pb.build_predicate(
|
|
87
|
+
self.include_files, self.ignore_files
|
|
88
|
+
)
|
|
86
89
|
|
|
87
90
|
def init(self, *args, **kwargs) -> None:
|
|
88
91
|
self.__init__(*args, **kwargs)
|
|
@@ -95,13 +98,16 @@ class FileTreeDisplay:
|
|
|
95
98
|
|
|
96
99
|
def update_predicates(self):
|
|
97
100
|
self.dir_filter = self.pb.build_predicate(self.include_dirs, self.ignore_dirs)
|
|
98
|
-
self.file_filter = self.pb.build_predicate(
|
|
101
|
+
self.file_filter = self.pb.build_predicate(
|
|
102
|
+
self.include_files, self.ignore_files
|
|
103
|
+
)
|
|
99
104
|
|
|
100
105
|
@staticmethod
|
|
101
|
-
def _nat_key(name: str) -> list[int |
|
|
106
|
+
def _nat_key(name: str) -> list[int | str | Any]:
|
|
102
107
|
"""Natural sorting key"""
|
|
103
|
-
return [
|
|
104
|
-
|
|
108
|
+
return [
|
|
109
|
+
int(part) if part.isdigit() else part.lower() for part in _NUM_SPLIT(name)
|
|
110
|
+
]
|
|
105
111
|
|
|
106
112
|
@staticmethod
|
|
107
113
|
def _lex_key(name: str) -> str:
|
|
@@ -127,7 +133,7 @@ class FileTreeDisplay:
|
|
|
127
133
|
|
|
128
134
|
tree_info = self.get_tree_info(iterator)
|
|
129
135
|
|
|
130
|
-
if self.save2file:
|
|
136
|
+
if self.save2file and filepath:
|
|
131
137
|
str2file(tree_info, filepath)
|
|
132
138
|
return filepath
|
|
133
139
|
|
|
@@ -141,8 +147,7 @@ class FileTreeDisplay:
|
|
|
141
147
|
lines.extend(list(iterator))
|
|
142
148
|
return '\n'.join(lines)
|
|
143
149
|
|
|
144
|
-
def build_tree(self, dir_path: str,
|
|
145
|
-
prefix: str = '') -> Generator[str, None, None]:
|
|
150
|
+
def build_tree(self, dir_path: str, prefix: str = '') -> Generator[str, None, None]:
|
|
146
151
|
"""Yields formatted directory tree lines, using a recursive DFS.
|
|
147
152
|
Intended order of appearance is with a preference to subdirectories first.
|
|
148
153
|
|
|
@@ -163,9 +168,10 @@ class FileTreeDisplay:
|
|
|
163
168
|
|
|
164
169
|
if sort_key is None:
|
|
165
170
|
if sort_key_name == 'custom':
|
|
166
|
-
raise ValueError(
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
raise ValueError(
|
|
172
|
+
"custom_sort function must be specified when sort_key_name='custom'"
|
|
173
|
+
)
|
|
174
|
+
raise ValueError(f'Invalid sort key name: {sort_key_name}')
|
|
169
175
|
|
|
170
176
|
try:
|
|
171
177
|
with os.scandir(dir_path) as entries:
|
|
@@ -181,7 +187,11 @@ class FileTreeDisplay:
|
|
|
181
187
|
append_file(name)
|
|
182
188
|
|
|
183
189
|
except (PermissionError, OSError) as e:
|
|
184
|
-
msg =
|
|
190
|
+
msg = (
|
|
191
|
+
'[Permission Denied]'
|
|
192
|
+
if isinstance(e, PermissionError)
|
|
193
|
+
else '[Error reading directory]'
|
|
194
|
+
)
|
|
185
195
|
yield f'{next_prefix}{msg}'
|
|
186
196
|
return
|
|
187
197
|
|
nano_dev_utils/timers.py
CHANGED
|
@@ -23,9 +23,12 @@ R = TypeVar('R')
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class Timer:
|
|
26
|
-
def __init__(
|
|
26
|
+
def __init__(
|
|
27
|
+
self, precision: int = 4, verbose: bool = False, printout: bool = False
|
|
28
|
+
):
|
|
27
29
|
self.precision = precision
|
|
28
30
|
self.verbose = verbose
|
|
31
|
+
self.printout = printout
|
|
29
32
|
|
|
30
33
|
def init(self, *args, **kwargs) -> None:
|
|
31
34
|
self.__init__(*args, **kwargs)
|
|
@@ -33,6 +36,9 @@ class Timer:
|
|
|
33
36
|
def update(self, attrs: dict[str, Any]) -> None:
|
|
34
37
|
update(self, attrs)
|
|
35
38
|
|
|
39
|
+
def res_formatter(self, elapsed_ns: float, *, precision: int = 4) -> str:
|
|
40
|
+
return self._duration_formatter(elapsed_ns, precision=precision)
|
|
41
|
+
|
|
36
42
|
def timeit(
|
|
37
43
|
self,
|
|
38
44
|
iterations: int = 1,
|
|
@@ -53,12 +59,14 @@ class Timer:
|
|
|
53
59
|
RP = ParamSpec('RP')
|
|
54
60
|
RR = TypeVar('RR')
|
|
55
61
|
|
|
56
|
-
precision = self.precision
|
|
62
|
+
precision, verbose, printout = self.precision, self.verbose, self.printout
|
|
63
|
+
check_timeout = self._check_timeout
|
|
64
|
+
duration_formatter = self._duration_formatter
|
|
65
|
+
formatted_msg = self._formatted_msg
|
|
57
66
|
|
|
58
67
|
def decorator(
|
|
59
68
|
func: Callable[RP, RR] | Callable[RP, Awaitable[RR]],
|
|
60
69
|
) -> Callable[RP, Any]:
|
|
61
|
-
verbose = self.verbose
|
|
62
70
|
if inspect.iscoroutinefunction(func):
|
|
63
71
|
async_func = cast(Callable[RP, Awaitable[RR]], func)
|
|
64
72
|
|
|
@@ -73,7 +81,7 @@ class Timer:
|
|
|
73
81
|
duration_ns = time.perf_counter_ns() - start_ns
|
|
74
82
|
total_elapsed_ns += duration_ns
|
|
75
83
|
|
|
76
|
-
|
|
84
|
+
check_timeout(
|
|
77
85
|
func_name,
|
|
78
86
|
i,
|
|
79
87
|
duration_ns,
|
|
@@ -82,12 +90,14 @@ class Timer:
|
|
|
82
90
|
per_iteration,
|
|
83
91
|
)
|
|
84
92
|
avg_elapsed_ns = total_elapsed_ns / iterations
|
|
85
|
-
duration_str =
|
|
93
|
+
duration_str = duration_formatter(avg_elapsed_ns, precision)
|
|
86
94
|
|
|
87
|
-
msg =
|
|
95
|
+
msg = formatted_msg(
|
|
88
96
|
func_name, args, kwargs, duration_str, iterations, verbose
|
|
89
97
|
)
|
|
90
98
|
lgr.info(msg)
|
|
99
|
+
if printout:
|
|
100
|
+
print(msg)
|
|
91
101
|
return cast(RR, result)
|
|
92
102
|
|
|
93
103
|
return cast(Callable[RP, Awaitable[RR]], async_wrapper)
|
|
@@ -104,7 +114,7 @@ class Timer:
|
|
|
104
114
|
result = sync_func(*args, **kwargs)
|
|
105
115
|
duration_ns = time.perf_counter_ns() - start_ns
|
|
106
116
|
total_elapsed_ns += duration_ns
|
|
107
|
-
|
|
117
|
+
check_timeout(
|
|
108
118
|
func_name,
|
|
109
119
|
i,
|
|
110
120
|
duration_ns,
|
|
@@ -113,11 +123,13 @@ class Timer:
|
|
|
113
123
|
per_iteration,
|
|
114
124
|
)
|
|
115
125
|
avg_elapsed_ns = total_elapsed_ns / iterations
|
|
116
|
-
duration_str =
|
|
117
|
-
msg =
|
|
126
|
+
duration_str = duration_formatter(avg_elapsed_ns, precision)
|
|
127
|
+
msg = formatted_msg(
|
|
118
128
|
func_name, args, kwargs, duration_str, iterations, verbose
|
|
119
129
|
)
|
|
120
130
|
lgr.info(msg)
|
|
131
|
+
if printout:
|
|
132
|
+
print(msg)
|
|
121
133
|
return cast(RR, result)
|
|
122
134
|
|
|
123
135
|
return cast(Callable[RP, RR], sync_wrapper)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nano_dev_utils
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.1
|
|
4
4
|
Summary: A collection of small Python utilities for developers.
|
|
5
5
|
Project-URL: Homepage, https://github.com/yaronday/nano_utils
|
|
6
6
|
Project-URL: Issues, https://github.com/yaronday/nano_utils/issues
|
|
@@ -26,9 +26,10 @@ This module provides a `Timer` class for measuring the execution time of code bl
|
|
|
26
26
|
|
|
27
27
|
#### `Timer` Class
|
|
28
28
|
|
|
29
|
-
* **`__init__(self, precision: int = 4, verbose: bool = False)`**: Initializes a `Timer` instance.
|
|
29
|
+
* **`__init__(self, precision: int = 4, verbose: bool = False, printout: bool = False)`**: Initializes a `Timer` instance.
|
|
30
30
|
* `precision`: The number of decimal places to record and display time durations. Defaults to 4.
|
|
31
31
|
* `verbose`: Optionally displays the function's positional arguments (args) and keyword arguments (kwargs). Defaults to `False`.
|
|
32
|
+
* `printout`: Allows printing to console.
|
|
32
33
|
|
|
33
34
|
* **`def timeit(
|
|
34
35
|
self,
|
|
@@ -47,15 +48,22 @@ This module provides a `Timer` class for measuring the execution time of code bl
|
|
|
47
48
|
* Records execution times
|
|
48
49
|
* Handles timeout conditions
|
|
49
50
|
* Calculates average execution time across iterations
|
|
50
|
-
*
|
|
51
|
+
* Logs the function name and execution time (with optional arguments)
|
|
51
52
|
* Returns the result of the original function (unless timeout occurs)
|
|
52
53
|
|
|
53
54
|
#### Example Usage:
|
|
54
55
|
|
|
55
56
|
```python
|
|
56
57
|
import time
|
|
58
|
+
import logging
|
|
57
59
|
from nano_dev_utils import timer
|
|
58
60
|
|
|
61
|
+
# This timer version uses a logger but also allows printing (if enabled), so it has to be configured in your app, for instance:
|
|
62
|
+
logging.basicConfig(filename='timer example.log',
|
|
63
|
+
level=logging.INFO, # DEBUG, WARNING, ERROR, CRITICAL
|
|
64
|
+
format='%(asctime)s - %(levelname)s: %(message)s',
|
|
65
|
+
datefmt='%d-%m-%Y %H:%M:%S')
|
|
66
|
+
|
|
59
67
|
# Basic timing
|
|
60
68
|
@timer.timeit()
|
|
61
69
|
def my_function(a, b=10):
|
|
@@ -64,17 +72,15 @@ def my_function(a, b=10):
|
|
|
64
72
|
return a + b
|
|
65
73
|
|
|
66
74
|
timer.init(precision=6, verbose=True)
|
|
67
|
-
'''
|
|
68
|
-
|
|
75
|
+
'''Alternative options:
|
|
76
|
+
timer.update({'precision': 6, 'verbose': True}) # 1. Using update method
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
The above config could be also achieved via explicit instantiation:
|
|
73
|
-
|
|
74
|
-
from nano_dev_utils.timers import Timer
|
|
75
|
-
timer = Timer(precision=6, verbose=True)
|
|
78
|
+
from nano_dev_utils.timers import Timer # 2. explicit instantiation
|
|
79
|
+
timer = Timer(precision=6, verbose=True)
|
|
76
80
|
'''
|
|
77
81
|
|
|
82
|
+
timer.update({'printout': True}) # allow printing to console
|
|
83
|
+
|
|
78
84
|
# Advanced usage with timeout and iterations
|
|
79
85
|
@timer.timeit(iterations=5, timeout=0.5, per_iteration=True)
|
|
80
86
|
def critical_function(x):
|
|
@@ -151,7 +157,7 @@ import logging
|
|
|
151
157
|
from nano_dev_utils import ports_release, PortsRelease
|
|
152
158
|
|
|
153
159
|
|
|
154
|
-
#
|
|
160
|
+
# configure the logger
|
|
155
161
|
logging.basicConfig(filename='port release.log',
|
|
156
162
|
level=logging.INFO, # DEBUG, WARNING, ERROR, CRITICAL
|
|
157
163
|
format='%(asctime)s - %(levelname)s: %(message)s',
|
|
@@ -170,8 +176,9 @@ ports_release.release_all()
|
|
|
170
176
|
|
|
171
177
|
### `file_tree_display.py`
|
|
172
178
|
|
|
173
|
-
This module provides a
|
|
174
|
-
It supports recursive traversal, customizable hierarchy styles, and
|
|
179
|
+
This module provides a utility for generating a visually structured directory tree.
|
|
180
|
+
It supports recursive traversal, customizable hierarchy styles, and inclusion / exclusion
|
|
181
|
+
patterns for directories and files.
|
|
175
182
|
Output can be displayed in the console or saved to a file.
|
|
176
183
|
|
|
177
184
|
|
|
@@ -180,11 +187,12 @@ Output can be displayed in the console or saved to a file.
|
|
|
180
187
|
- Recursively displays and logs directory trees
|
|
181
188
|
- Efficient directory traversal
|
|
182
189
|
- Blazing fast (see Benchmarks below)
|
|
183
|
-
- Generates human-readable file tree structure
|
|
190
|
+
- Generates human-readable file tree structure
|
|
191
|
+
- Supports including / ignoring specific directories or files via pattern matching
|
|
184
192
|
- Customizable tree display output
|
|
185
193
|
- Optionally saves the resulting tree to a text file
|
|
186
|
-
-
|
|
187
|
-
|
|
194
|
+
- Lightweight, flexible and easily configurable
|
|
195
|
+
|
|
188
196
|
|
|
189
197
|
## Benchmarks
|
|
190
198
|
|
|
@@ -244,11 +252,13 @@ filepath = str(Path(target_path, filename))
|
|
|
244
252
|
|
|
245
253
|
ftd = FileTreeDisplay(root_dir=root,
|
|
246
254
|
ignore_dirs=['.git', 'node_modules', '.idea'],
|
|
247
|
-
ignore_files=
|
|
255
|
+
ignore_files=['.gitignore', '*.toml'],
|
|
256
|
+
style='—',
|
|
248
257
|
include_dirs=['src', 'tests', 'snapshots'],
|
|
249
258
|
filepath=filepath,
|
|
250
259
|
sort_key_name='custom',
|
|
251
260
|
custom_sort=(lambda x: any(ext in x.lower() for ext in ('jpg', 'png'))),
|
|
261
|
+
files_first=True,
|
|
252
262
|
reverse=True
|
|
253
263
|
)
|
|
254
264
|
ftd.file_tree_display()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
nano_dev_utils/__init__.py,sha256=bJNCUyssMVyNmOey-god8A2kElC4nCR9B5DsdvUrKWw,1014
|
|
2
|
+
nano_dev_utils/common.py,sha256=MsY5n9lSOjvEu0wGvmd2zQamFLLbtbjodZku5W9tuWE,5873
|
|
3
|
+
nano_dev_utils/dynamic_importer.py,sha256=-Mh76366lI_mP2QA_jxiVfcKCHOHeukS_j4v7fTh0xw,1028
|
|
4
|
+
nano_dev_utils/file_tree_display.py,sha256=RMd2l1FZgO__9EmCSKRkZ6s7tYpCx6Fe7e83fAxNxg0,8234
|
|
5
|
+
nano_dev_utils/release_ports.py,sha256=yLWMMbN6j6kWtGTg-Nynn37-Q4b2rxkls9hs2sqeZjA,6081
|
|
6
|
+
nano_dev_utils/timers.py,sha256=5Ci6IgdEfwIvRtQes4byab1GJowLdfnurUBUxorSgIc,7840
|
|
7
|
+
nano_dev_utils-1.4.1.dist-info/METADATA,sha256=sfJDvXpotS86VX6o1XjnwFY3CDoTNUpJkDlLoOpFsGM,12133
|
|
8
|
+
nano_dev_utils-1.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
9
|
+
nano_dev_utils-1.4.1.dist-info/licenses/LICENSE,sha256=Muenl7Bw_LdtHZtlOMAP7Kt97gDCq8WWp2605eDWhHU,1089
|
|
10
|
+
nano_dev_utils-1.4.1.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
nano_dev_utils/__init__.py,sha256=bJNCUyssMVyNmOey-god8A2kElC4nCR9B5DsdvUrKWw,1014
|
|
2
|
-
nano_dev_utils/common.py,sha256=bNgiaBP5kQUxfEUN3HYp1_TnwG-SRvsiqu67yAG5Y4o,5585
|
|
3
|
-
nano_dev_utils/dynamic_importer.py,sha256=-Mh76366lI_mP2QA_jxiVfcKCHOHeukS_j4v7fTh0xw,1028
|
|
4
|
-
nano_dev_utils/file_tree_display.py,sha256=0pfDr1QgyPJZbtl8mKNfJO0T3Jl2vUrwt8syVn_PhsI,8192
|
|
5
|
-
nano_dev_utils/release_ports.py,sha256=yLWMMbN6j6kWtGTg-Nynn37-Q4b2rxkls9hs2sqeZjA,6081
|
|
6
|
-
nano_dev_utils/timers.py,sha256=Ko2RR96-Sb6hIQAPxiwCUPAK2uwJ1dP_9Teym8lx_lo,7350
|
|
7
|
-
nano_dev_utils-1.4.0.dist-info/METADATA,sha256=z4PfsxOWteGXmLuJS5MtivqCKox9LR6wUKTjhelw9_c,11642
|
|
8
|
-
nano_dev_utils-1.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
9
|
-
nano_dev_utils-1.4.0.dist-info/licenses/LICENSE,sha256=Muenl7Bw_LdtHZtlOMAP7Kt97gDCq8WWp2605eDWhHU,1089
|
|
10
|
-
nano_dev_utils-1.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|