nnlogging 0.1.0__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 nnlogging might be problematic. Click here for more details.
- nnlogging/__init__.py +7 -0
- nnlogging/shell.py +307 -0
- nnlogging/utils.py +212 -0
- nnlogging-0.1.0.dist-info/METADATA +24 -0
- nnlogging-0.1.0.dist-info/RECORD +6 -0
- nnlogging-0.1.0.dist-info/WHEEL +4 -0
nnlogging/__init__.py
ADDED
nnlogging/shell.py
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"""nnlog.shell"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from logging import Handler, Logger
|
|
6
|
+
|
|
7
|
+
from aim import Run
|
|
8
|
+
from aim.sdk.types import AimObject
|
|
9
|
+
from rich.console import Console as RichConsole
|
|
10
|
+
from rich.console import ConsoleRenderable
|
|
11
|
+
from rich.progress import Progress as RichProgress
|
|
12
|
+
from rich.progress import TaskID
|
|
13
|
+
|
|
14
|
+
from .utils import (
|
|
15
|
+
get_aim_run,
|
|
16
|
+
get_rich_handler,
|
|
17
|
+
get_rich_progress,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
__all__ = ["Shell"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Shell:
|
|
24
|
+
name: str = "nnlog"
|
|
25
|
+
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
name: str | None = None,
|
|
29
|
+
level: int = logging.INFO,
|
|
30
|
+
propagate: bool = False,
|
|
31
|
+
):
|
|
32
|
+
self.name = name or self.name
|
|
33
|
+
self.level: int = level
|
|
34
|
+
self.propagate: bool = propagate
|
|
35
|
+
|
|
36
|
+
self.logger: Logger = logging.getLogger(self.name)
|
|
37
|
+
self.consoles: dict[str, RichConsole] = dict()
|
|
38
|
+
self.handlers: dict[str, Handler] = dict()
|
|
39
|
+
self.progresses: dict[str, RichProgress] = dict()
|
|
40
|
+
self.tasks: dict[str, dict[str, TaskID]] = dict()
|
|
41
|
+
self.aim_run: Run | None = None
|
|
42
|
+
|
|
43
|
+
self.configure_logger()
|
|
44
|
+
|
|
45
|
+
def configure_logger(
|
|
46
|
+
self,
|
|
47
|
+
level: int | None = None,
|
|
48
|
+
propagate: bool | None = None,
|
|
49
|
+
):
|
|
50
|
+
if level is not None:
|
|
51
|
+
self.level = level
|
|
52
|
+
if propagate is not None:
|
|
53
|
+
self.propagate = propagate
|
|
54
|
+
self.logger.setLevel(self.level)
|
|
55
|
+
self.logger.propagate = self.propagate
|
|
56
|
+
|
|
57
|
+
def add_console(
|
|
58
|
+
self,
|
|
59
|
+
consoles: Mapping[str, RichConsole],
|
|
60
|
+
):
|
|
61
|
+
self.consoles.update(consoles)
|
|
62
|
+
|
|
63
|
+
def add_handler(
|
|
64
|
+
self,
|
|
65
|
+
handlers: Mapping[str, Handler],
|
|
66
|
+
):
|
|
67
|
+
self.handlers.update(handlers)
|
|
68
|
+
|
|
69
|
+
def add_progress(
|
|
70
|
+
self,
|
|
71
|
+
progresses: Mapping[str, RichProgress],
|
|
72
|
+
):
|
|
73
|
+
self.progresses.update(progresses)
|
|
74
|
+
|
|
75
|
+
def build_handler_from_console(
|
|
76
|
+
self,
|
|
77
|
+
*names: str,
|
|
78
|
+
**kwargs,
|
|
79
|
+
):
|
|
80
|
+
if len(names) == 0:
|
|
81
|
+
names = tuple(n for n in self.consoles.keys())
|
|
82
|
+
|
|
83
|
+
handlers = {
|
|
84
|
+
name: get_rich_handler(
|
|
85
|
+
console=self.consoles[name],
|
|
86
|
+
name=name,
|
|
87
|
+
**kwargs,
|
|
88
|
+
)
|
|
89
|
+
for name in names
|
|
90
|
+
}
|
|
91
|
+
self.add_handler(handlers)
|
|
92
|
+
self.sync_handlers()
|
|
93
|
+
|
|
94
|
+
def build_progress_from_console(
|
|
95
|
+
self,
|
|
96
|
+
*names: str,
|
|
97
|
+
**kwargs,
|
|
98
|
+
):
|
|
99
|
+
if len(names) == 0:
|
|
100
|
+
names = tuple(n for n in self.consoles.keys())
|
|
101
|
+
|
|
102
|
+
progresses = {
|
|
103
|
+
name: get_rich_progress(
|
|
104
|
+
console=self.consoles[name],
|
|
105
|
+
**kwargs,
|
|
106
|
+
)
|
|
107
|
+
for name in names
|
|
108
|
+
}
|
|
109
|
+
self.add_progress(progresses)
|
|
110
|
+
|
|
111
|
+
def sync_handlers(self):
|
|
112
|
+
self.logger.handlers.clear()
|
|
113
|
+
for hdlr in self.handlers.values():
|
|
114
|
+
self.logger.addHandler(hdlr)
|
|
115
|
+
|
|
116
|
+
def add_task(
|
|
117
|
+
self,
|
|
118
|
+
task_name: str,
|
|
119
|
+
description: str,
|
|
120
|
+
start: bool = True,
|
|
121
|
+
total: float | None = 100,
|
|
122
|
+
completed: float = 0,
|
|
123
|
+
):
|
|
124
|
+
self.tasks[task_name] = dict()
|
|
125
|
+
for progress_name in self.progresses.keys():
|
|
126
|
+
task_id = self.progresses[progress_name].add_task(
|
|
127
|
+
description=description,
|
|
128
|
+
start=start,
|
|
129
|
+
total=total,
|
|
130
|
+
completed=completed, # pyright: ignore[reportArgumentType]
|
|
131
|
+
)
|
|
132
|
+
self.tasks[task_name].update({progress_name: task_id})
|
|
133
|
+
|
|
134
|
+
def start_progress(self, *names: str):
|
|
135
|
+
if len(names) == 0:
|
|
136
|
+
names = tuple(n for n in self.progresses.keys())
|
|
137
|
+
|
|
138
|
+
for name in names:
|
|
139
|
+
self.progresses[name].start()
|
|
140
|
+
|
|
141
|
+
def stop_progress(self, *names: str):
|
|
142
|
+
if len(names) == 0:
|
|
143
|
+
names = tuple(n for n in self.progresses.keys())
|
|
144
|
+
|
|
145
|
+
for progress_name in names:
|
|
146
|
+
self.progresses[progress_name].stop()
|
|
147
|
+
del self.progresses[progress_name]
|
|
148
|
+
for task_name in self.tasks.keys():
|
|
149
|
+
del self.tasks[task_name][progress_name]
|
|
150
|
+
|
|
151
|
+
def update_task(
|
|
152
|
+
self,
|
|
153
|
+
task_name: str,
|
|
154
|
+
advance: float | None = None,
|
|
155
|
+
total: float | None = None,
|
|
156
|
+
completed: float | None = None,
|
|
157
|
+
):
|
|
158
|
+
for progress_name, progress in self.progresses.items():
|
|
159
|
+
task_id = self.tasks[task_name][progress_name]
|
|
160
|
+
progress.update(
|
|
161
|
+
task_id=task_id,
|
|
162
|
+
advance=advance,
|
|
163
|
+
total=total,
|
|
164
|
+
completed=completed,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def log(
|
|
168
|
+
self,
|
|
169
|
+
level: int,
|
|
170
|
+
msg: object,
|
|
171
|
+
*args: object,
|
|
172
|
+
stacklevel: int = 2,
|
|
173
|
+
**kwargs,
|
|
174
|
+
):
|
|
175
|
+
if isinstance(msg, ConsoleRenderable):
|
|
176
|
+
self.debug(f"Parsing {msg} to consoles ...")
|
|
177
|
+
for console in self.consoles.values():
|
|
178
|
+
console.print(msg, *args, **kwargs)
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
self.logger.log(
|
|
182
|
+
level=level,
|
|
183
|
+
msg=msg,
|
|
184
|
+
*args,
|
|
185
|
+
stacklevel=stacklevel,
|
|
186
|
+
**kwargs,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
def debug(
|
|
190
|
+
self,
|
|
191
|
+
msg: object,
|
|
192
|
+
*args: object,
|
|
193
|
+
stacklevel: int = 3,
|
|
194
|
+
**kwargs,
|
|
195
|
+
):
|
|
196
|
+
self.log(
|
|
197
|
+
logging.DEBUG,
|
|
198
|
+
msg,
|
|
199
|
+
*args,
|
|
200
|
+
stacklevel=stacklevel,
|
|
201
|
+
**kwargs,
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def info(
|
|
205
|
+
self,
|
|
206
|
+
msg: object,
|
|
207
|
+
*args: object,
|
|
208
|
+
stacklevel: int = 3,
|
|
209
|
+
**kwargs,
|
|
210
|
+
):
|
|
211
|
+
self.log(
|
|
212
|
+
logging.INFO,
|
|
213
|
+
msg,
|
|
214
|
+
*args,
|
|
215
|
+
stacklevel=stacklevel,
|
|
216
|
+
**kwargs,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
def warn(
|
|
220
|
+
self,
|
|
221
|
+
msg: object,
|
|
222
|
+
*args: object,
|
|
223
|
+
stacklevel: int = 3,
|
|
224
|
+
**kwargs,
|
|
225
|
+
):
|
|
226
|
+
self.log(
|
|
227
|
+
logging.WARN,
|
|
228
|
+
msg,
|
|
229
|
+
*args,
|
|
230
|
+
stacklevel=stacklevel,
|
|
231
|
+
**kwargs,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
def error(
|
|
235
|
+
self,
|
|
236
|
+
msg: object,
|
|
237
|
+
*args: object,
|
|
238
|
+
stacklevel: int = 3,
|
|
239
|
+
**kwargs,
|
|
240
|
+
):
|
|
241
|
+
self.log(
|
|
242
|
+
logging.ERROR,
|
|
243
|
+
msg,
|
|
244
|
+
*args,
|
|
245
|
+
stacklevel=stacklevel,
|
|
246
|
+
**kwargs,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
def exception(
|
|
250
|
+
self,
|
|
251
|
+
msg: object,
|
|
252
|
+
*args,
|
|
253
|
+
exc_info: bool = True,
|
|
254
|
+
stacklevel: int = 3,
|
|
255
|
+
**kwargs,
|
|
256
|
+
):
|
|
257
|
+
self.log(
|
|
258
|
+
logging.ERROR,
|
|
259
|
+
msg,
|
|
260
|
+
*args,
|
|
261
|
+
exc_info=exc_info,
|
|
262
|
+
stacklevel=stacklevel,
|
|
263
|
+
**kwargs,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def add_aimrun(
|
|
267
|
+
self,
|
|
268
|
+
**kwargs,
|
|
269
|
+
):
|
|
270
|
+
self.aim_run = get_aim_run(**kwargs)
|
|
271
|
+
|
|
272
|
+
def update_aimrun_metadata(
|
|
273
|
+
self,
|
|
274
|
+
label: str,
|
|
275
|
+
metadata: dict[str, object],
|
|
276
|
+
):
|
|
277
|
+
if self.aim_run is None:
|
|
278
|
+
self.error(
|
|
279
|
+
"`aim_run` is not initialized",
|
|
280
|
+
stacklevel=4,
|
|
281
|
+
exc_info=ValueError(f"`aim_run` is {self.aim_run}"),
|
|
282
|
+
)
|
|
283
|
+
else:
|
|
284
|
+
self.aim_run[label] = metadata
|
|
285
|
+
|
|
286
|
+
def track(
|
|
287
|
+
self,
|
|
288
|
+
value: object,
|
|
289
|
+
name: str | None = None,
|
|
290
|
+
step: int | None = None,
|
|
291
|
+
epoch: int | None = None,
|
|
292
|
+
context: AimObject | None = None,
|
|
293
|
+
):
|
|
294
|
+
if self.aim_run is None:
|
|
295
|
+
self.error(
|
|
296
|
+
"`aim_run` is not initialized",
|
|
297
|
+
stacklevel=4,
|
|
298
|
+
exc_info=ValueError(f"`aim_run` is {self.aim_run}"),
|
|
299
|
+
)
|
|
300
|
+
else:
|
|
301
|
+
self.aim_run.track(
|
|
302
|
+
value,
|
|
303
|
+
name=name,
|
|
304
|
+
step=step,
|
|
305
|
+
epoch=epoch,
|
|
306
|
+
context=context,
|
|
307
|
+
)
|
nnlogging/utils.py
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""nnlog.utils"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Collection
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from os import PathLike
|
|
7
|
+
from types import NoneType
|
|
8
|
+
from typing import Callable, Literal, TextIO
|
|
9
|
+
|
|
10
|
+
from rich.console import Console as RichConsole
|
|
11
|
+
from rich.highlighter import Highlighter
|
|
12
|
+
from rich.progress import ProgressColumn
|
|
13
|
+
from rich.text import Text
|
|
14
|
+
from aim import Repo, Run
|
|
15
|
+
|
|
16
|
+
type FormatTimeCallable = Callable[[datetime], Text]
|
|
17
|
+
type StrPath = str | PathLike[str]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"get_rich_console",
|
|
22
|
+
"get_rich_handler",
|
|
23
|
+
"get_rich_progress",
|
|
24
|
+
"get_aim_run",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_rich_console(
|
|
29
|
+
sink: TextIO | None = None,
|
|
30
|
+
width: int | None = None,
|
|
31
|
+
height: int | None = None,
|
|
32
|
+
tab_size: int = 4,
|
|
33
|
+
soft_wrap: bool = True,
|
|
34
|
+
color_system: Literal["auto", "standard", "truecolor"] | None = "auto",
|
|
35
|
+
markup: bool = True,
|
|
36
|
+
highlighter: Highlighter | None = None,
|
|
37
|
+
record: bool = False,
|
|
38
|
+
):
|
|
39
|
+
from sys import stderr
|
|
40
|
+
|
|
41
|
+
if sink is None:
|
|
42
|
+
sink = stderr
|
|
43
|
+
|
|
44
|
+
if highlighter is not None:
|
|
45
|
+
highlight = True
|
|
46
|
+
else:
|
|
47
|
+
from rich.highlighter import NullHighlighter
|
|
48
|
+
|
|
49
|
+
highlight = False
|
|
50
|
+
highlighter = NullHighlighter()
|
|
51
|
+
|
|
52
|
+
console = RichConsole(
|
|
53
|
+
file=sink,
|
|
54
|
+
width=width,
|
|
55
|
+
height=height,
|
|
56
|
+
tab_size=tab_size,
|
|
57
|
+
soft_wrap=soft_wrap,
|
|
58
|
+
color_system=color_system,
|
|
59
|
+
markup=markup,
|
|
60
|
+
highlight=highlight,
|
|
61
|
+
highlighter=highlighter,
|
|
62
|
+
record=record,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
return console
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def get_rich_handler(
|
|
69
|
+
console: RichConsole | None = None,
|
|
70
|
+
name: str | None = None,
|
|
71
|
+
fmt: str | logging.Formatter = "%(message)s",
|
|
72
|
+
level: str | int = logging.INFO,
|
|
73
|
+
show_time: bool = True,
|
|
74
|
+
log_time_format: str | FormatTimeCallable = "[%x %X]",
|
|
75
|
+
omit_repeated_times: bool = True,
|
|
76
|
+
show_level: bool = True,
|
|
77
|
+
show_path: bool = True,
|
|
78
|
+
enable_link_path: bool = True,
|
|
79
|
+
markup: bool = True,
|
|
80
|
+
highlighter: Highlighter | None = None,
|
|
81
|
+
rich_tracebacks: bool = True,
|
|
82
|
+
tracebacks_width: int | None = None,
|
|
83
|
+
tracebacks_code_width: int | None = 88,
|
|
84
|
+
tracebacks_extra_lines: int = 3,
|
|
85
|
+
tracebacks_word_wrap: bool = True,
|
|
86
|
+
tracebacks_max_frames: int = 100,
|
|
87
|
+
tracebacks_show_locals: bool = False,
|
|
88
|
+
locals_max_length: int = 10,
|
|
89
|
+
locals_max_string: int = 80,
|
|
90
|
+
):
|
|
91
|
+
from rich.logging import RichHandler
|
|
92
|
+
|
|
93
|
+
if console is None:
|
|
94
|
+
console = get_rich_console()
|
|
95
|
+
|
|
96
|
+
if isinstance(fmt, str):
|
|
97
|
+
fmt = logging.Formatter(fmt)
|
|
98
|
+
|
|
99
|
+
handler = RichHandler(
|
|
100
|
+
console=console,
|
|
101
|
+
level=level,
|
|
102
|
+
show_time=show_time,
|
|
103
|
+
log_time_format=log_time_format,
|
|
104
|
+
omit_repeated_times=omit_repeated_times,
|
|
105
|
+
show_level=show_level,
|
|
106
|
+
show_path=show_path,
|
|
107
|
+
enable_link_path=enable_link_path,
|
|
108
|
+
markup=markup,
|
|
109
|
+
highlighter=highlighter,
|
|
110
|
+
rich_tracebacks=rich_tracebacks,
|
|
111
|
+
tracebacks_width=tracebacks_width,
|
|
112
|
+
tracebacks_code_width=tracebacks_code_width,
|
|
113
|
+
tracebacks_extra_lines=tracebacks_extra_lines,
|
|
114
|
+
tracebacks_word_wrap=tracebacks_word_wrap,
|
|
115
|
+
tracebacks_max_frames=tracebacks_max_frames,
|
|
116
|
+
tracebacks_show_locals=tracebacks_show_locals,
|
|
117
|
+
locals_max_length=locals_max_length,
|
|
118
|
+
locals_max_string=locals_max_string,
|
|
119
|
+
)
|
|
120
|
+
handler.name = name
|
|
121
|
+
handler.setFormatter(fmt=fmt)
|
|
122
|
+
return handler
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def get_rich_progress(
|
|
126
|
+
console: RichConsole | None = None,
|
|
127
|
+
columns: Collection[str | ProgressColumn] | None = None,
|
|
128
|
+
expand: bool = False,
|
|
129
|
+
auto_refresh: bool = True,
|
|
130
|
+
refresh_per_second: float = 10,
|
|
131
|
+
speed_estimate_period: float = 3600,
|
|
132
|
+
transient: bool = False,
|
|
133
|
+
redirect_stderr: bool = True,
|
|
134
|
+
redirect_stdout: bool = True,
|
|
135
|
+
):
|
|
136
|
+
from rich.progress import Progress
|
|
137
|
+
|
|
138
|
+
def get_default_rich_progress_columns():
|
|
139
|
+
from rich.progress import (
|
|
140
|
+
BarColumn,
|
|
141
|
+
SpinnerColumn,
|
|
142
|
+
TaskProgressColumn,
|
|
143
|
+
TextColumn,
|
|
144
|
+
TimeRemainingColumn,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
SpinnerColumn(
|
|
149
|
+
spinner_name="dots",
|
|
150
|
+
style="progress.spinner",
|
|
151
|
+
finished_text=" ",
|
|
152
|
+
),
|
|
153
|
+
TextColumn(
|
|
154
|
+
text_format="{task.description}",
|
|
155
|
+
style="progress.description",
|
|
156
|
+
justify="left",
|
|
157
|
+
markup=True,
|
|
158
|
+
),
|
|
159
|
+
BarColumn(bar_width=40),
|
|
160
|
+
TaskProgressColumn(
|
|
161
|
+
text_format="{task.percentage:>3.0f}%",
|
|
162
|
+
text_format_no_percentage="",
|
|
163
|
+
style="progress.percentage",
|
|
164
|
+
justify="right",
|
|
165
|
+
markup=True,
|
|
166
|
+
show_speed=True,
|
|
167
|
+
),
|
|
168
|
+
TimeRemainingColumn(
|
|
169
|
+
compact=False,
|
|
170
|
+
elapsed_when_finished=False,
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if console is None:
|
|
175
|
+
console = get_rich_console()
|
|
176
|
+
|
|
177
|
+
if columns is None:
|
|
178
|
+
columns = get_default_rich_progress_columns()
|
|
179
|
+
|
|
180
|
+
return Progress(
|
|
181
|
+
*columns,
|
|
182
|
+
console=console,
|
|
183
|
+
auto_refresh=auto_refresh,
|
|
184
|
+
refresh_per_second=refresh_per_second,
|
|
185
|
+
speed_estimate_period=speed_estimate_period,
|
|
186
|
+
transient=transient,
|
|
187
|
+
expand=expand,
|
|
188
|
+
redirect_stderr=redirect_stderr,
|
|
189
|
+
redirect_stdout=redirect_stdout,
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_aim_run(
|
|
194
|
+
run_hash: str | None = None,
|
|
195
|
+
repo: str | Repo | None = None,
|
|
196
|
+
read_only: bool = False,
|
|
197
|
+
experiment: str | None = None,
|
|
198
|
+
force_resume: bool = False,
|
|
199
|
+
system_tracking_interval: float | None = 10,
|
|
200
|
+
log_system_params: bool = False,
|
|
201
|
+
capture_terminal_logs: bool = False,
|
|
202
|
+
):
|
|
203
|
+
return Run(
|
|
204
|
+
run_hash=run_hash,
|
|
205
|
+
repo=repo,
|
|
206
|
+
read_only=read_only,
|
|
207
|
+
experiment=experiment,
|
|
208
|
+
force_resume=force_resume,
|
|
209
|
+
system_tracking_interval=system_tracking_interval,
|
|
210
|
+
log_system_params=log_system_params,
|
|
211
|
+
capture_terminal_logs=capture_terminal_logs,
|
|
212
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nnlogging
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Add your description here
|
|
5
|
+
Requires-Python: <3.13,>=3.12
|
|
6
|
+
Requires-Dist: aim>=3.29.1
|
|
7
|
+
Requires-Dist: rich>=14.1.0
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: twine>=6.2.0; extra == 'dev'
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# nnlog
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## *Workflow Overview*
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## *Functions Overview*
|
|
23
|
+
|
|
24
|
+

|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
nnlogging/__init__.py,sha256=rK6DT6Jtc63odOR8D5xvxRmBtg3EoCkOOC9-2xIaxKg,84
|
|
2
|
+
nnlogging/shell.py,sha256=Y7yv-paD0IS-31_HwnvRA70SY6tE6lERVM2ryc2BgtU,7559
|
|
3
|
+
nnlogging/utils.py,sha256=dgRi4Q9moF6RtyYz_W762o9dqPC8UvhfCr0JwJifppg,5928
|
|
4
|
+
nnlogging-0.1.0.dist-info/METADATA,sha256=NWzHYl_h1frGimfhzW70YwaGDkmCm3Qp1DAZziy5rjE,433
|
|
5
|
+
nnlogging-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
6
|
+
nnlogging-0.1.0.dist-info/RECORD,,
|