nnlogging 0.1.2__py3-none-any.whl → 0.1.4__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 (46) hide show
  1. nnlogging/__init__.py +3 -15
  2. nnlogging/exceptions/__init__.py +15 -0
  3. nnlogging/exceptions/branch_exists.py +29 -0
  4. nnlogging/exceptions/branch_not_found.py +29 -0
  5. nnlogging/exceptions/task_exists.py +31 -0
  6. nnlogging/exceptions/task_not_found.py +29 -0
  7. nnlogging/global_.py +322 -0
  8. nnlogging/options/__init__.py +31 -0
  9. nnlogging/options/branch_config.py +19 -0
  10. nnlogging/options/log_option.py +34 -0
  11. nnlogging/options/logger_config.py +16 -0
  12. nnlogging/options/rich_console.py +44 -0
  13. nnlogging/options/rich_handler.py +47 -0
  14. nnlogging/options/rich_progress.py +62 -0
  15. nnlogging/options/run_config.py +27 -0
  16. nnlogging/options/task_option.py +17 -0
  17. nnlogging/options/track_option.py +19 -0
  18. nnlogging/shell.py +92 -273
  19. nnlogging/shell_funcs/__init__.py +4 -0
  20. nnlogging/shell_funcs/branch_.py +79 -0
  21. nnlogging/{utils/shell_funcs → shell_funcs}/logger_.py +55 -62
  22. nnlogging/shell_funcs/run_.py +84 -0
  23. nnlogging/{utils/shell_funcs → shell_funcs}/task_.py +42 -42
  24. nnlogging/typings/aliases.py +8 -56
  25. nnlogging/typings/exts.py +15 -0
  26. nnlogging/typings/protocols.py +43 -1
  27. nnlogging/utils/factories.py +112 -0
  28. nnlogging/utils/helpers.py +61 -26
  29. {nnlogging-0.1.2.dist-info → nnlogging-0.1.4.dist-info}/METADATA +25 -32
  30. nnlogging-0.1.4.dist-info/RECORD +31 -0
  31. nnlogging/shell_protocol.py +0 -86
  32. nnlogging/typings/__init__.py +0 -41
  33. nnlogging/typings/exceptions.py +0 -10
  34. nnlogging/typings/generics.py +0 -23
  35. nnlogging/utils/__init__.py +0 -83
  36. nnlogging/utils/exception/__init__.py +0 -11
  37. nnlogging/utils/exception/branch_exists.py +0 -49
  38. nnlogging/utils/exception/branch_not_found.py +0 -49
  39. nnlogging/utils/exception/task_exists.py +0 -54
  40. nnlogging/utils/exception/task_not_found.py +0 -49
  41. nnlogging/utils/factory_funcs/rich_.py +0 -154
  42. nnlogging/utils/factory_funcs/shell_.py +0 -192
  43. nnlogging/utils/shell_funcs/branch_.py +0 -164
  44. nnlogging/utils/shell_funcs/run_.py +0 -97
  45. nnlogging-0.1.2.dist-info/RECORD +0 -24
  46. {nnlogging-0.1.2.dist-info → nnlogging-0.1.4.dist-info}/WHEEL +0 -0
@@ -0,0 +1,79 @@
1
+ import sys
2
+ from dataclasses import asdict, replace
3
+ from typing import Literal, cast
4
+
5
+ from nnlogging.exceptions import (
6
+ call_branch_exists_error,
7
+ call_branch_not_found_error,
8
+ )
9
+ from nnlogging.options import BranchConfigOptionDict
10
+ from nnlogging.typings.exts import Unpack
11
+ from nnlogging.typings.protocols import ShellProtocol, Sink
12
+ from nnlogging.utils.factories import get_branch
13
+
14
+ __all__ = [
15
+ "branch_configure",
16
+ "branch_add",
17
+ "branch_remove",
18
+ ]
19
+
20
+
21
+ def branch_configure(
22
+ inst: ShellProtocol,
23
+ **kwargs: Unpack[BranchConfigOptionDict],
24
+ ):
25
+ inst.branch_config = replace(
26
+ inst.branch_config,
27
+ **kwargs,
28
+ )
29
+
30
+
31
+ def branch_add(
32
+ inst: ShellProtocol,
33
+ name: str,
34
+ sink: Sink | Literal["stderr", "stdout"] = "stderr",
35
+ **kwargs: Unpack[BranchConfigOptionDict],
36
+ ):
37
+ if name in inst.branches:
38
+ e = call_branch_exists_error(
39
+ inst,
40
+ name,
41
+ stacklevel=2,
42
+ )
43
+ if inst.strict:
44
+ raise e
45
+
46
+ else:
47
+ if isinstance(sink, str) and sink in ("stderr", "stdout"):
48
+ sink = cast(Sink, getattr(sys, sink))
49
+ branch = get_branch(
50
+ sink,
51
+ **(asdict(inst.branch_config) | kwargs), # pyright: ignore[reportArgumentType]
52
+ )
53
+ inst.branches[name] = branch
54
+ if inst.logger is not None:
55
+ inst.logger.addHandler(branch["handler"])
56
+
57
+
58
+ def branch_remove(
59
+ inst: ShellProtocol,
60
+ name: str,
61
+ ):
62
+ if name not in inst.branches:
63
+ e = call_branch_not_found_error(
64
+ inst,
65
+ name,
66
+ stacklevel=2,
67
+ )
68
+ if inst.strict:
69
+ raise e
70
+
71
+ else:
72
+ branch = inst.branches[name]
73
+ branch["handler"].close()
74
+ branch["tasks"].clear()
75
+ if branch["progress"] is not None:
76
+ branch["progress"].stop()
77
+ if inst.logger is not None:
78
+ inst.logger.removeHandler(branch["handler"])
79
+ del inst.branches[name]
@@ -1,20 +1,41 @@
1
1
  import logging
2
+ from dataclasses import asdict, replace
2
3
 
3
4
  from rich.console import ConsoleRenderable as RichConsoleRenderable
4
5
 
5
- from nnlogging.shell_protocol import ShellProtocol
6
- from nnlogging.typings import ConsolePrintOptions, LogOptions, Omitable
7
- from nnlogging.utils.factory_funcs.shell_ import LoggerConfig, get_logging_logger
8
- from nnlogging.utils.helpers import evolve_
6
+ from nnlogging.options import (
7
+ LoggerConfigOptionDict,
8
+ LoggingLogOptionDict,
9
+ LogOptionDict,
10
+ RichPrintOptionDict,
11
+ )
12
+ from nnlogging.typings.exts import Unpack
13
+ from nnlogging.typings.protocols import ShellProtocol
14
+ from nnlogging.utils.factories import get_logging_logger
15
+ from nnlogging.utils.helpers import (
16
+ filter_by_typeddict,
17
+ inc_stacklevel,
18
+ inject_excinfo,
19
+ )
20
+
21
+ __all__ = [
22
+ "logger_configure",
23
+ "log",
24
+ "debug",
25
+ "info",
26
+ "warn",
27
+ "error",
28
+ "critical",
29
+ "exception",
30
+ ]
9
31
 
10
32
 
11
33
  def _logger_open(
12
34
  inst: ShellProtocol,
13
- /,
14
35
  ):
15
36
  if inst.logger is None:
16
37
  logging.captureWarnings(True)
17
- inst.logger = get_logging_logger(inst.logger_config)
38
+ inst.logger = get_logging_logger(**asdict(inst.logger_config))
18
39
  for name in inst.branches:
19
40
  branch = inst.branches[name]
20
41
  inst.logger.addHandler(branch["handler"])
@@ -23,55 +44,46 @@ def _logger_open(
23
44
 
24
45
  def _logger_close(
25
46
  inst: ShellProtocol,
26
- /,
27
47
  ):
28
48
  if inst.logger is not None:
29
49
  logging.captureWarnings(False)
30
50
  for handler in inst.logger.handlers[:]:
31
51
  inst.logger.removeHandler(handler)
32
52
  handler.close()
33
- # TODO: add `filter` support in v0.2.0
34
- # inst.logger.filters.clear()
53
+ inst.logger.filters.clear()
35
54
  inst.logger.setLevel(logging.NOTSET)
36
- inst.logger.propagate = False
55
+ inst.logger.propagate = True
37
56
  inst.logger = None
38
57
 
39
58
 
40
59
  def logger_configure(
41
60
  inst: ShellProtocol,
42
- /,
43
- config: LoggerConfig | None = None,
44
- *,
45
- name: Omitable[str] = ...,
46
- level: Omitable[int | str] = ...,
47
- propagate: Omitable[bool] = ...,
61
+ **kwargs: Unpack[LoggerConfigOptionDict],
48
62
  ):
49
63
  _logger_close(inst)
50
- inst.logger_config = evolve_(
51
- config or inst.logger_config,
52
- name=name,
53
- level=level,
54
- propagate=propagate,
64
+ inst.logger_config = replace(
65
+ inst.logger_config,
66
+ **kwargs,
55
67
  )
56
68
 
57
69
 
58
70
  def log(
59
71
  inst: ShellProtocol,
60
- /,
61
72
  level: int,
62
73
  msg: object,
63
74
  *args: object,
64
- log_options: LogOptions | None = None,
65
- console_options: ConsolePrintOptions | None = None,
75
+ **kwargs: Unpack[LogOptionDict],
66
76
  ):
67
77
  _logger_open(inst)
68
78
  assert inst.logger is not None
69
79
  match msg:
70
80
  case RichConsoleRenderable():
71
- debug(
81
+ inst.logger.log(
82
+ level,
83
+ "Sending %s to %s branches ...",
84
+ msg,
72
85
  inst,
73
- f"Sending {repr(msg)} to branches ...",
74
- log_options=log_options or LogOptions(),
86
+ **inc_stacklevel(filter_by_typeddict(kwargs, LoggingLogOptionDict)),
75
87
  )
76
88
  for name in inst.branches:
77
89
  branch = inst.branches[name]
@@ -79,121 +91,102 @@ def log(
79
91
  branch["console"].print(
80
92
  msg,
81
93
  *args,
82
- **(console_options or ConsolePrintOptions()),
94
+ **filter_by_typeddict(kwargs, RichPrintOptionDict),
83
95
  )
84
96
  case _:
85
97
  inst.logger.log(
86
98
  level,
87
99
  msg,
88
100
  *args,
89
- **(log_options or LogOptions()),
101
+ **inc_stacklevel(filter_by_typeddict(kwargs, LoggingLogOptionDict)),
90
102
  )
91
103
 
92
104
 
93
105
  def debug(
94
106
  inst: ShellProtocol,
95
- /,
96
107
  msg: object,
97
108
  *args: object,
98
- log_options: LogOptions | None = None,
99
- console_options: ConsolePrintOptions | None = None,
109
+ **kwargs: Unpack[LogOptionDict],
100
110
  ):
101
111
  log(
102
112
  inst,
103
113
  logging.DEBUG,
104
114
  msg,
105
115
  *args,
106
- log_options=log_options,
107
- console_options=console_options,
116
+ **inc_stacklevel(kwargs),
108
117
  )
109
118
 
110
119
 
111
120
  def info(
112
121
  inst: ShellProtocol,
113
- /,
114
122
  msg: object,
115
123
  *args: object,
116
- log_options: LogOptions | None = None,
117
- console_options: ConsolePrintOptions | None = None,
124
+ **kwargs: Unpack[LogOptionDict],
118
125
  ):
119
126
  log(
120
127
  inst,
121
128
  logging.INFO,
122
129
  msg,
123
130
  *args,
124
- log_options=log_options,
125
- console_options=console_options,
131
+ **inc_stacklevel(kwargs),
126
132
  )
127
133
 
128
134
 
129
135
  def warn(
130
136
  inst: ShellProtocol,
131
- /,
132
137
  msg: object,
133
138
  *args: object,
134
- log_options: LogOptions | None = None,
135
- console_options: ConsolePrintOptions | None = None,
139
+ **kwargs: Unpack[LogOptionDict],
136
140
  ):
137
141
  log(
138
142
  inst,
139
- logging.WARNING,
143
+ logging.WARN,
140
144
  msg,
141
145
  *args,
142
- log_options=log_options,
143
- console_options=console_options,
146
+ **inc_stacklevel(kwargs),
144
147
  )
145
148
 
146
149
 
147
150
  def error(
148
151
  inst: ShellProtocol,
149
- /,
150
152
  msg: object,
151
153
  *args: object,
152
- log_options: LogOptions | None = None,
153
- console_options: ConsolePrintOptions | None = None,
154
+ **kwargs: Unpack[LogOptionDict],
154
155
  ):
155
156
  log(
156
157
  inst,
157
158
  logging.ERROR,
158
159
  msg,
159
160
  *args,
160
- log_options=log_options,
161
- console_options=console_options,
161
+ **inc_stacklevel(kwargs),
162
162
  )
163
163
 
164
164
 
165
165
  def critical(
166
166
  inst: ShellProtocol,
167
- /,
168
167
  msg: object,
169
168
  *args: object,
170
- log_options: LogOptions | None = None,
171
- console_options: ConsolePrintOptions | None = None,
169
+ **kwargs: Unpack[LogOptionDict],
172
170
  ):
173
171
  log(
174
172
  inst,
175
173
  logging.CRITICAL,
176
174
  msg,
177
175
  *args,
178
- log_options=log_options,
179
- console_options=console_options,
176
+ **inc_stacklevel(kwargs),
180
177
  )
181
178
 
182
179
 
183
180
  def exception(
184
181
  inst: ShellProtocol,
185
- /,
186
182
  msg: object,
187
183
  *args: object,
188
- log_options: LogOptions | None = None,
189
- console_options: ConsolePrintOptions | None = None,
184
+ **kwargs: Unpack[LogOptionDict],
190
185
  ):
191
- default_log_options = LogOptions(exc_info=True)
192
186
  log(
193
187
  inst,
194
- logging.CRITICAL,
188
+ logging.ERROR,
195
189
  msg,
196
190
  *args,
197
- log_options=default_log_options | (log_options or LogOptions()),
198
- console_options=console_options,
191
+ **inc_stacklevel(inject_excinfo(kwargs)),
199
192
  )
@@ -0,0 +1,84 @@
1
+ from dataclasses import asdict, replace
2
+
3
+ from aim.storage.types import AimObject
4
+
5
+ from nnlogging.options import RunConfigOptionDict, TrackOptionDict
6
+ from nnlogging.typings.exts import Unpack
7
+ from nnlogging.typings.protocols import ShellProtocol
8
+ from nnlogging.utils.factories import get_aim_run
9
+
10
+ __all__ = [
11
+ "run_configure",
12
+ "track",
13
+ "add_tag",
14
+ "remove_tag",
15
+ "update_metadata",
16
+ ]
17
+
18
+
19
+ def _run_open(
20
+ inst: ShellProtocol,
21
+ ):
22
+ if inst.run is None:
23
+ inst.run = get_aim_run(**asdict(inst.run_config))
24
+
25
+
26
+ def _run_close(
27
+ inst: ShellProtocol,
28
+ ):
29
+ if inst.run is not None:
30
+ inst.run.close()
31
+ del inst.run
32
+ inst.run = None
33
+
34
+
35
+ def run_configure(
36
+ inst: ShellProtocol,
37
+ **kwargs: Unpack[RunConfigOptionDict],
38
+ ):
39
+ _run_close(inst)
40
+ inst.run_config = replace(
41
+ inst.run_config,
42
+ **kwargs,
43
+ )
44
+
45
+
46
+ def track(
47
+ inst: ShellProtocol,
48
+ value: object,
49
+ **kwargs: Unpack[TrackOptionDict],
50
+ ):
51
+ _run_open(inst)
52
+ assert inst.run is not None
53
+ inst.run.track(
54
+ value,
55
+ **kwargs, # pyright: ignore[reportArgumentType]
56
+ )
57
+
58
+
59
+ def add_tag(
60
+ inst: ShellProtocol,
61
+ tag: str,
62
+ ):
63
+ _run_open(inst)
64
+ assert inst.run is not None
65
+ inst.run.add_tag(tag)
66
+
67
+
68
+ def remove_tag(
69
+ inst: ShellProtocol,
70
+ tag: str,
71
+ ):
72
+ _run_open(inst)
73
+ assert inst.run is not None
74
+ inst.run.remove_tag(tag)
75
+
76
+
77
+ def update_metadata(
78
+ inst: ShellProtocol,
79
+ key: str,
80
+ value: AimObject,
81
+ ):
82
+ _run_open(inst)
83
+ assert inst.run is not None
84
+ inst.run[key] = value
@@ -1,48 +1,57 @@
1
- from nnlogging.shell_protocol import ShellProtocol
2
- from nnlogging.utils.exception import (
3
- raise_task_exists_error,
4
- raise_task_not_found_error,
5
- )
6
- from nnlogging.utils.factory_funcs.rich_ import get_rich_progress
1
+ from dataclasses import asdict
2
+
3
+ from nnlogging.exceptions import call_task_exists_error, call_task_not_found_error
4
+ from nnlogging.options import RichProgressOptionDict, TaskOptionDict
5
+ from nnlogging.typings.exts import Unpack
6
+ from nnlogging.typings.protocols import ShellProtocol
7
+ from nnlogging.utils.factories import get_rich_progress
8
+ from nnlogging.utils.helpers import filter_by_typeddict
9
+
10
+ __all__ = [
11
+ "task_add",
12
+ "task_remove",
13
+ "advance",
14
+ ]
7
15
 
8
16
 
9
17
  def _task_open(
10
18
  inst: ShellProtocol,
11
- /,
12
19
  name: str,
13
20
  ):
14
21
  for branch_name in inst.branches:
15
22
  branch = inst.branches[branch_name]
16
23
  if name in branch["tasks"]:
17
- raise_task_exists_error(
24
+ e = call_task_exists_error(
18
25
  inst,
19
26
  branch_name,
20
27
  name,
21
28
  stacklevel=2,
22
29
  )
23
- if branch["progress"] is None:
24
- progress = get_rich_progress(
25
- branch["console"],
26
- columns=inst.branch_config.columns,
27
- transient=inst.branch_config.transient,
28
- refresh_per_second=inst.branch_config.refresh_per_second,
29
- speed_estimate_period=inst.branch_config.speed_estimate_period,
30
- default_column_markup=inst.branch_config.default_column_markup,
31
- )
32
- progress.start()
33
- branch["progress"] = progress
30
+ if inst.strict:
31
+ raise e
32
+
33
+ else:
34
+ if branch["progress"] is None:
35
+ progress = get_rich_progress(
36
+ branch["console"],
37
+ **filter_by_typeddict(
38
+ asdict(inst.branch_config),
39
+ RichProgressOptionDict,
40
+ ),
41
+ )
42
+ progress.start()
43
+ branch["progress"] = progress
34
44
 
35
45
 
36
46
  def _task_close(
37
47
  inst: ShellProtocol,
38
- /,
39
48
  name: str,
40
49
  ):
41
- task_found = False
50
+ _task_found = False
42
51
  for branch_name in inst.branches:
43
52
  branch = inst.branches[branch_name]
44
53
  if name in branch["tasks"]:
45
- task_found = True
54
+ _task_found = True
46
55
  assert branch["progress"] is not None # definitely
47
56
  task_id = branch["tasks"][name]
48
57
  if branch["progress"]._tasks[task_id].finished: # pyright: ignore[reportPrivateUsage]
@@ -50,44 +59,37 @@ def _task_close(
50
59
  if branch["progress"].finished:
51
60
  branch["progress"].stop()
52
61
  branch["progress"] = None
53
- if not task_found:
54
- raise_task_not_found_error(
62
+ if not _task_found:
63
+ e = call_task_not_found_error(
55
64
  inst,
56
65
  name,
57
66
  stacklevel=2,
58
67
  )
68
+ if inst.strict:
69
+ raise e
59
70
 
60
71
 
61
72
  def task_add(
62
73
  inst: ShellProtocol,
63
- /,
64
74
  name: str,
65
- *,
66
- desc: str,
67
- total: float | None,
68
- done: float = 0,
75
+ **kwargs: Unpack[TaskOptionDict],
69
76
  ):
70
77
  _task_open(inst, name)
71
78
  for branch_name in inst.branches:
72
79
  branch = inst.branches[branch_name]
73
- assert branch["progress"] is not None # definitely
74
- task_id = branch["progress"].add_task(
75
- description=desc,
76
- total=total,
77
- completed=done, # pyright: ignore[reportArgumentType]
78
- )
80
+ assert branch["progress"] is not None
81
+ task_id = branch["progress"].add_task(**kwargs) # pyright: ignore[reportArgumentType]
79
82
  branch["tasks"][name] = task_id
80
83
 
81
84
 
82
85
  def task_remove(
83
86
  inst: ShellProtocol,
84
- /,
85
87
  name: str,
86
88
  ):
87
89
  for branch_name in inst.branches:
88
90
  branch = inst.branches[branch_name]
89
91
  if name in branch["tasks"]:
90
- assert branch["progress"] is not None # definitely
92
+ assert branch["progress"] is not None
91
93
  task_id = branch["tasks"][name]
92
94
  branch["progress"]._tasks[task_id].finished_time = 0 # pyright: ignore[reportPrivateUsage]
93
95
  _task_close(inst, name)
@@ -95,17 +97,15 @@ def task_remove(
95
97
 
96
98
  def advance(
97
99
  inst: ShellProtocol,
98
- /,
99
100
  name: str,
100
- *,
101
- advance: float,
101
+ value: float,
102
102
  ):
103
103
  for branch_name in inst.branches:
104
104
  branch = inst.branches[branch_name]
105
- assert branch["progress"] is not None # definitely
105
+ assert branch["progress"] is not None
106
106
  task_id = branch["tasks"][name]
107
107
  branch["progress"].advance(
108
108
  task_id=task_id,
109
- advance=advance,
109
+ advance=value,
110
110
  )
111
111
  _task_close(inst, name)
@@ -1,66 +1,18 @@
1
- import sys
2
- from collections.abc import Mapping
3
1
  from datetime import datetime
4
- from types import TracebackType
5
- from typing import Callable, Literal, TypeAlias, TypedDict
2
+ from os import PathLike
3
+ from typing import Callable, TypeAlias, TypedDict
6
4
 
7
5
  from rich.console import Console as RichConsole
8
6
  from rich.logging import RichHandler
9
7
  from rich.progress import Progress as RichProgress, TaskID as RichTaskID
10
- from rich.style import Style as RichStyle
11
8
  from rich.text import Text as RichText
12
9
 
13
- from nnlogging.typings.generics import Pathlike
14
- from nnlogging.typings.protocols import TerminalWritable, Writable
15
-
16
- if sys.version_info >= (3, 11):
17
- from typing import NotRequired, Required
18
- else:
19
- from typing_extensions import NotRequired, Required
20
-
21
-
22
- Sink: TypeAlias = Writable | TerminalWritable
23
- GenericPath = Pathlike[str] | Pathlike[bytes]
10
+ StrPath: TypeAlias = str | PathLike[str]
24
11
  FormatTimeCallable: TypeAlias = Callable[[datetime], RichText]
25
12
 
26
13
 
27
- class Branch(TypedDict):
28
- console: Required[RichConsole]
29
- handler: Required[RichHandler]
30
- tasks: Required[dict[str, RichTaskID]]
31
- progress: Required[RichProgress | None]
32
-
33
-
34
- JustifyMethod = Literal["default", "left", "center", "right", "full"]
35
- OverflowMethod = Literal["fold", "crop", "ellipsis", "ignore"]
36
-
37
-
38
- class ConsolePrintOptions(TypedDict):
39
- sep: NotRequired[str]
40
- end: NotRequired[str]
41
- style: NotRequired[str | RichStyle | None]
42
- justify: NotRequired[JustifyMethod | None]
43
- overflow: NotRequired[OverflowMethod | None]
44
- no_wrap: NotRequired[bool | None]
45
- emoji: NotRequired[bool | None]
46
- markup: NotRequired[bool | None]
47
- highlight: NotRequired[bool | None]
48
- width: NotRequired[int | None]
49
- height: NotRequired[int | None]
50
- crop: NotRequired[bool]
51
- soft_wrap: NotRequired[bool | None]
52
- new_line_start: NotRequired[bool]
53
-
54
-
55
- _SysExcInfo: TypeAlias = (
56
- tuple[type[BaseException], BaseException, TracebackType | None]
57
- | tuple[None, None, None]
58
- )
59
- ExcInfo: TypeAlias = None | bool | _SysExcInfo | BaseException
60
-
61
-
62
- class LogOptions(TypedDict):
63
- exc_info: NotRequired[ExcInfo]
64
- stack_info: NotRequired[bool]
65
- stacklevel: NotRequired[int]
66
- extra: NotRequired[Mapping[str, object] | None]
14
+ class Branch(TypedDict, total=True):
15
+ console: RichConsole
16
+ handler: RichHandler
17
+ tasks: dict[str, RichTaskID]
18
+ progress: RichProgress | None
@@ -0,0 +1,15 @@
1
+ import sys
2
+
3
+ if sys.version_info >= (3, 11):
4
+ from typing import Never, NotRequired, Required, Unpack
5
+ else:
6
+ from typing_extensions import Never, NotRequired, Required, Unpack
7
+
8
+
9
+ __all__ = [
10
+ # py311
11
+ "NotRequired",
12
+ "Required",
13
+ "Unpack",
14
+ "Never",
15
+ ]