encommon 0.13.1__py3-none-any.whl → 0.15.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.
Files changed (63) hide show
  1. encommon/__init__.py +2 -7
  2. encommon/colors/__init__.py +14 -0
  3. encommon/colors/color.py +518 -0
  4. encommon/colors/test/__init__.py +6 -0
  5. encommon/colors/test/test_color.py +189 -0
  6. encommon/config/config.py +83 -30
  7. encommon/config/files.py +16 -13
  8. encommon/config/logger.py +10 -5
  9. encommon/config/params.py +47 -31
  10. encommon/config/paths.py +15 -12
  11. encommon/config/test/__init__.py +1 -1
  12. encommon/config/test/test_config.py +15 -17
  13. encommon/config/test/test_files.py +8 -7
  14. encommon/config/test/test_logger.py +21 -15
  15. encommon/config/test/test_paths.py +12 -11
  16. encommon/config/utils.py +9 -3
  17. encommon/conftest.py +33 -22
  18. encommon/crypts/params.py +46 -11
  19. encommon/crypts/test/test_crypts.py +5 -5
  20. encommon/crypts/test/test_hashes.py +2 -1
  21. encommon/times/__init__.py +5 -3
  22. encommon/times/common.py +4 -3
  23. encommon/times/params.py +103 -45
  24. encommon/times/parse.py +39 -12
  25. encommon/times/test/test_duration.py +3 -2
  26. encommon/times/test/test_parse.py +16 -9
  27. encommon/times/test/test_time.py +123 -0
  28. encommon/times/test/test_timer.py +5 -4
  29. encommon/times/test/test_timers.py +10 -9
  30. encommon/times/test/test_unitime.py +23 -0
  31. encommon/times/test/test_window.py +4 -3
  32. encommon/times/test/test_windows.py +7 -6
  33. encommon/times/{times.py → time.py} +129 -22
  34. encommon/times/timer.py +10 -10
  35. encommon/times/timers.py +3 -3
  36. encommon/times/unitime.py +57 -0
  37. encommon/times/window.py +31 -31
  38. encommon/times/windows.py +10 -10
  39. encommon/types/__init__.py +20 -2
  40. encommon/types/classes.py +84 -0
  41. encommon/types/lists.py +33 -0
  42. encommon/types/notate.py +2 -1
  43. encommon/types/strings.py +34 -4
  44. encommon/types/test/test_classes.py +74 -0
  45. encommon/types/test/test_empty.py +2 -1
  46. encommon/types/test/test_lists.py +23 -0
  47. encommon/types/test/test_strings.py +15 -3
  48. encommon/types/types.py +20 -0
  49. encommon/utils/__init__.py +4 -0
  50. encommon/utils/paths.py +5 -6
  51. encommon/utils/sample.py +118 -41
  52. encommon/utils/stdout.py +53 -7
  53. encommon/utils/test/test_paths.py +3 -3
  54. encommon/utils/test/test_sample.py +128 -29
  55. encommon/utils/test/test_stdout.py +92 -28
  56. encommon/version.txt +1 -1
  57. {encommon-0.13.1.dist-info → encommon-0.15.0.dist-info}/METADATA +1 -1
  58. encommon-0.15.0.dist-info/RECORD +84 -0
  59. {encommon-0.13.1.dist-info → encommon-0.15.0.dist-info}/WHEEL +1 -1
  60. encommon/times/test/test_times.py +0 -89
  61. encommon-0.13.1.dist-info/RECORD +0 -73
  62. {encommon-0.13.1.dist-info → encommon-0.15.0.dist-info}/LICENSE +0 -0
  63. {encommon-0.13.1.dist-info → encommon-0.15.0.dist-info}/top_level.txt +0 -0
encommon/config/paths.py CHANGED
@@ -10,13 +10,14 @@ is permitted, for more information consult the project license file.
10
10
  from copy import deepcopy
11
11
  from glob import glob
12
12
  from pathlib import Path
13
- from typing import Any
14
13
  from typing import Optional
15
14
  from typing import TYPE_CHECKING
16
15
 
17
16
  from .files import ConfigFile
18
17
  from .utils import config_path
19
18
  from .utils import config_paths
19
+ from ..types import DictStrAny
20
+ from ..types import sort_dict
20
21
 
21
22
  if TYPE_CHECKING:
22
23
  from ..utils.common import PATHABLE
@@ -69,7 +70,7 @@ class ConfigPaths:
69
70
  paths: tuple[Path, ...]
70
71
  config: dict[str, ConfigPath]
71
72
 
72
- __merged: Optional[dict[str, Any]]
73
+ __merge: Optional[DictStrAny]
73
74
 
74
75
 
75
76
  def __init__(
@@ -87,13 +88,13 @@ class ConfigPaths:
87
88
  str(x): ConfigPath(x)
88
89
  for x in self.paths}
89
90
 
90
- self.__merged = None
91
+ self.__merge = None
91
92
 
92
93
 
93
94
  @property
94
- def merged(
95
+ def merge(
95
96
  self,
96
- ) -> dict[str, Any]:
97
+ ) -> DictStrAny:
97
98
  """
98
99
  Return the configuration in dictionary format for paths.
99
100
 
@@ -101,12 +102,12 @@ class ConfigPaths:
101
102
  """
102
103
 
103
104
  config = self.config
104
- merged = self.__merged
105
+ merge = self.__merge
105
106
 
106
- if merged is not None:
107
- return deepcopy(merged)
107
+ if merge is not None:
108
+ return deepcopy(merge)
108
109
 
109
- merged = {}
110
+ merge = {}
110
111
 
111
112
 
112
113
  for path in config.values():
@@ -115,9 +116,11 @@ class ConfigPaths:
115
116
 
116
117
  for key, file in items:
117
118
 
118
- merged[key] = file.config
119
+ merge[key] = file.config
119
120
 
120
121
 
121
- self.__merged = merged
122
+ merge = sort_dict(merge)
122
123
 
123
- return deepcopy(merged)
124
+ self.__merge = merge
125
+
126
+ return deepcopy(merge)
@@ -13,4 +13,4 @@ from pathlib import Path
13
13
 
14
14
  SAMPLES = (
15
15
  Path(__file__).parent
16
- .joinpath('samples'))
16
+ / 'samples')
@@ -11,15 +11,13 @@ from pathlib import Path
11
11
  from typing import TYPE_CHECKING
12
12
 
13
13
  from . import SAMPLES
14
- from ..logger import Logger
15
- from ..params import Params
16
- from ... import ENPYRWS
17
14
  from ... import PROJECT
18
- from ...crypts import Crypts
19
15
  from ...types import inrepr
20
16
  from ...types import instr
17
+ from ...types import lattrs
21
18
  from ...utils import load_sample
22
19
  from ...utils import prep_sample
20
+ from ...utils.sample import ENPYRWS
23
21
 
24
22
  if TYPE_CHECKING:
25
23
  from ..config import Config
@@ -38,7 +36,7 @@ def test_Config(
38
36
  """
39
37
 
40
38
 
41
- attrs = list(config.__dict__)
39
+ attrs = lattrs(config)
42
40
 
43
41
  assert attrs == [
44
42
  '_Config__model',
@@ -62,13 +60,9 @@ def test_Config(
62
60
  config)
63
61
 
64
62
 
65
- assert instr(
66
- 'files.ConfigFiles object',
67
- config.files)
63
+ assert config.files.merge
68
64
 
69
- assert instr(
70
- 'paths.ConfigPaths object',
71
- config.paths)
65
+ assert config.paths.merge
72
66
 
73
67
  assert len(config.cargs) == 1
74
68
 
@@ -76,13 +70,17 @@ def test_Config(
76
70
 
77
71
  assert len(config.config) == 3
78
72
 
79
- assert config.model is Params
73
+ assert len(config.basic) == 3
74
+
75
+ assert len(config.merge) == 5
76
+
77
+ assert callable(config.model)
80
78
 
81
- assert isinstance(config.params, Params)
79
+ assert config.params
82
80
 
83
- assert isinstance(config.logger, Logger)
81
+ assert config.logger
84
82
 
85
- assert isinstance(config.crypts, Crypts)
83
+ assert config.crypts
86
84
 
87
85
 
88
86
  replaces = {
@@ -90,7 +88,7 @@ def test_Config(
90
88
  'PROJECT': PROJECT}
91
89
 
92
90
  sample_path = (
93
- f'{SAMPLES}/config.json')
91
+ SAMPLES / 'config.json')
94
92
 
95
93
  sample = load_sample(
96
94
  path=sample_path,
@@ -102,7 +100,7 @@ def test_Config(
102
100
  content=config.config,
103
101
  replace=replaces)
104
102
 
105
- assert sample == expect
103
+ assert expect == sample
106
104
 
107
105
 
108
106
 
@@ -16,6 +16,7 @@ from ..files import ConfigFile
16
16
  from ..files import ConfigFiles
17
17
  from ...types import inrepr
18
18
  from ...types import instr
19
+ from ...types import lattrs
19
20
 
20
21
 
21
22
 
@@ -49,7 +50,7 @@ def test_ConfigFile(
49
50
  f'{config_path}/config.yml')
50
51
 
51
52
 
52
- attrs = list(file.__dict__)
53
+ attrs = lattrs(file)
53
54
 
54
55
  assert attrs == [
55
56
  'path',
@@ -83,12 +84,12 @@ def test_ConfigFiles(
83
84
  """
84
85
 
85
86
 
86
- attrs = list(files.__dict__)
87
+ attrs = lattrs(files)
87
88
 
88
89
  assert attrs == [
89
90
  'paths',
90
91
  'config',
91
- '_ConfigFiles__merged']
92
+ '_ConfigFiles__merge']
92
93
 
93
94
 
94
95
  assert inrepr(
@@ -106,7 +107,7 @@ def test_ConfigFiles(
106
107
 
107
108
  assert len(files.config) == 2
108
109
 
109
- assert files.merged == {
110
+ assert files.merge == {
110
111
  'name': 'Bruce Wayne'}
111
112
 
112
113
 
@@ -120,7 +121,7 @@ def test_ConfigFiles_cover(
120
121
  :param files: Custom fixture for the configuration files.
121
122
  """
122
123
 
123
- merged1 = files.merged
124
- merged2 = files.merged
124
+ merge1 = files.merge
125
+ merge2 = files.merge
125
126
 
126
- assert merged1 is not merged2
127
+ assert merge1 is not merge2
@@ -16,10 +16,12 @@ from pytest import fixture
16
16
  from ..logger import Logger
17
17
  from ..logger import Message
18
18
  from ..params import LoggerParams
19
+ from ...times import Time
19
20
  from ...times.common import UNIXMPOCH
20
21
  from ...times.common import UNIXSPOCH
21
22
  from ...types import inrepr
22
23
  from ...types import instr
24
+ from ...types import lattrs
23
25
  from ...utils import strip_ansi
24
26
 
25
27
 
@@ -69,7 +71,7 @@ def test_Message() -> None:
69
71
  elapsed=3.69420)
70
72
 
71
73
 
72
- attrs = list(message.__dict__)
74
+ attrs = lattrs(message)
73
75
 
74
76
  assert attrs == [
75
77
  '_Message__level',
@@ -139,7 +141,7 @@ def test_Logger(
139
141
  """
140
142
 
141
143
 
142
- attrs = list(logger.__dict__)
144
+ attrs = lattrs(logger)
143
145
 
144
146
  assert attrs == [
145
147
  '_Logger__params',
@@ -162,19 +164,19 @@ def test_Logger(
162
164
  logger)
163
165
 
164
166
 
165
- assert logger.params is not None
167
+ assert logger.params
166
168
 
167
169
  assert logger.stdo_level == 'info'
168
170
 
169
171
  assert logger.file_level == 'info'
170
172
 
171
- assert logger.file_path is not None
173
+ assert logger.file_path
172
174
 
173
- assert logger.started is False
175
+ assert not logger.started
174
176
 
175
- assert logger.logger_stdo is not None
177
+ assert logger.logger_stdo
176
178
 
177
- assert logger.logger_file is not None
179
+ assert logger.logger_file
178
180
 
179
181
 
180
182
  logger.log_d(msg='pytest')
@@ -196,6 +198,8 @@ def test_Logger_cover(
196
198
  :param caplog: pytest object for capturing log message.
197
199
  """
198
200
 
201
+ time = Time('now')
202
+
199
203
 
200
204
  def _logger_logs() -> None:
201
205
  logger.log_d(msg='pytest')
@@ -203,6 +207,7 @@ def test_Logger_cover(
203
207
  logger.log_e(msg='pytest')
204
208
  logger.log_i(msg='pytest')
205
209
  logger.log_w(msg='pytest')
210
+ logger.log_i(elapsed=time)
206
211
 
207
212
 
208
213
  def _logger_stdo() -> _CAPLOG:
@@ -229,16 +234,16 @@ def test_Logger_cover(
229
234
 
230
235
  _logger_logs()
231
236
 
232
- assert len(_logger_stdo()) == 5
233
- assert len(_logger_file()) == 5
237
+ assert len(_logger_stdo()) == 6
238
+ assert len(_logger_file()) == 6
234
239
 
235
240
  logger.stop()
236
241
 
237
242
 
238
243
  _logger_logs()
239
244
 
240
- assert len(_logger_stdo()) == 5
241
- assert len(_logger_file()) == 5
245
+ assert len(_logger_stdo()) == 6
246
+ assert len(_logger_file()) == 6
242
247
 
243
248
 
244
249
  logger.start()
@@ -256,13 +261,14 @@ def test_Logger_cover(
256
261
  assert message in str(stdo)
257
262
  assert message in str(file)
258
263
 
259
- assert len(_logger_stdo()) == 6
260
- assert len(_logger_file()) == 6
264
+ assert len(_logger_stdo()) == 7
265
+ assert len(_logger_file()) == 7
266
+
261
267
 
262
268
  logger.stop()
263
269
 
264
270
 
265
271
  _logger_logs()
266
272
 
267
- assert len(_logger_stdo()) == 6
268
- assert len(_logger_file()) == 6
273
+ assert len(_logger_stdo()) == 7
274
+ assert len(_logger_file()) == 7
@@ -14,12 +14,13 @@ from pytest import fixture
14
14
  from . import SAMPLES
15
15
  from ..paths import ConfigPath
16
16
  from ..paths import ConfigPaths
17
- from ... import ENPYRWS
18
17
  from ... import PROJECT
19
18
  from ...types import inrepr
20
19
  from ...types import instr
20
+ from ...types import lattrs
21
21
  from ...utils import load_sample
22
22
  from ...utils import prep_sample
23
+ from ...utils.sample import ENPYRWS
23
24
 
24
25
 
25
26
 
@@ -52,7 +53,7 @@ def test_ConfigPath(
52
53
  path = ConfigPath(config_path)
53
54
 
54
55
 
55
- attrs = list(path.__dict__)
56
+ attrs = lattrs(path)
56
57
 
57
58
  assert attrs == [
58
59
  'path',
@@ -86,11 +87,11 @@ def test_ConfigPaths(
86
87
  """
87
88
 
88
89
 
89
- attrs = list(paths.__dict__)
90
+ attrs = lattrs(paths)
90
91
 
91
92
  assert attrs == [
92
93
  'paths', 'config',
93
- '_ConfigPaths__merged']
94
+ '_ConfigPaths__merge']
94
95
 
95
96
 
96
97
  assert inrepr(
@@ -113,19 +114,19 @@ def test_ConfigPaths(
113
114
  'PROJECT': PROJECT}
114
115
 
115
116
  sample_path = (
116
- f'{SAMPLES}/paths.json')
117
+ SAMPLES / 'paths.json')
117
118
 
118
119
  sample = load_sample(
119
120
  path=sample_path,
120
121
  update=ENPYRWS,
121
- content=paths.merged,
122
+ content=paths.merge,
122
123
  replace=replaces)
123
124
 
124
125
  expect = prep_sample(
125
- content=paths.merged,
126
+ content=paths.merge,
126
127
  replace=replaces)
127
128
 
128
- assert sample == expect
129
+ assert expect == sample
129
130
 
130
131
 
131
132
 
@@ -138,7 +139,7 @@ def test_ConfigPaths_cover(
138
139
  :param paths: Custom fixture for the configuration paths.
139
140
  """
140
141
 
141
- merged1 = paths.merged
142
- merged2 = paths.merged
142
+ merge1 = paths.merge
143
+ merge2 = paths.merge
143
144
 
144
- assert merged1 is not merged2
145
+ assert merge1 is not merge2
encommon/config/utils.py CHANGED
@@ -8,7 +8,6 @@ is permitted, for more information consult the project license file.
8
8
 
9
9
 
10
10
  from pathlib import Path
11
- from typing import Any
12
11
  from typing import Optional
13
12
  from typing import TYPE_CHECKING
14
13
 
@@ -17,6 +16,7 @@ from yaml import load
17
16
 
18
17
  from .. import PROJECT
19
18
  from .. import WORKSPACE
19
+ from ..types import DictStrAny
20
20
  from ..utils import read_text
21
21
  from ..utils import resolve_path
22
22
  from ..utils import resolve_paths
@@ -29,7 +29,7 @@ if TYPE_CHECKING:
29
29
 
30
30
  def config_load(
31
31
  path: str | Path,
32
- ) -> dict[str, Any]:
32
+ ) -> DictStrAny:
33
33
  """
34
34
  Load configuration using the directory or file provided.
35
35
 
@@ -84,8 +84,14 @@ def config_paths(
84
84
  :returns: New resolved filesystem path object instances.
85
85
  """
86
86
 
87
+ if replace is None:
88
+ replace = {}
89
+
90
+ replace = dict(replace)
91
+
87
92
  replace = {
88
93
  'PROJECT': PROJECT,
89
94
  'WORKSPACE': WORKSPACE}
90
95
 
91
- return resolve_paths(paths, replace)
96
+ return resolve_paths(
97
+ paths, replace)
encommon/conftest.py CHANGED
@@ -27,31 +27,42 @@ def config_factory(
27
27
  :returns: Newly constructed instance of related class.
28
28
  """
29
29
 
30
+ content = (
31
+ f"""
32
+
33
+ enconfig:
34
+ paths:
35
+ - '{SAMPLES}/stark'
36
+ - '{SAMPLES}/wayne'
37
+
38
+ enlogger:
39
+ stdo_level: info
40
+
41
+ encrypts:
42
+ phrases:
43
+ default:
44
+ phrase: phrase
45
+
46
+ """) # noqa: LIT003
47
+
48
+ config_path = (
49
+ tmp_path / 'config.yml')
50
+
51
+ config_log = (
52
+ tmp_path / 'config.log')
53
+
30
54
  save_text(
31
- f'{tmp_path}/config.yml',
32
- content=(
33
- 'enconfig:\n'
34
- ' paths:\n'
35
- f" - '{SAMPLES}/stark'\n"
36
- f" - '{SAMPLES}/wayne'\n"
37
- 'enlogger:\n'
38
- ' stdo_level: info\n'
39
- 'encrypts:\n'
40
- ' phrases:\n'
41
- ' default:\n'
42
- ' phrase: phrase\n'))
43
-
44
- config_log = f'{tmp_path}/config.log'
45
-
46
- cargs = {
47
- 'enlogger/file_path': config_log,
48
- 'enlogger/file_level': 'info'}
49
-
50
- sargs = {
51
- 'custom/parameter': 'fart'}
55
+ config_path, content)
56
+
57
+ logger = {
58
+ 'file_path': config_log,
59
+ 'file_level': 'info'}
60
+
61
+ cargs = {'enlogger': logger}
62
+ sargs = {'cus/tom': 'fart'}
52
63
 
53
64
  return Config(
54
- files=f'{tmp_path}/config.yml',
65
+ config_path,
55
66
  cargs=cargs,
56
67
  sargs=sargs)
57
68
 
encommon/crypts/params.py CHANGED
@@ -7,30 +7,65 @@ is permitted, for more information consult the project license file.
7
7
 
8
8
 
9
9
 
10
- from pydantic import BaseModel
10
+ from typing import Annotated
11
+ from typing import Optional
12
+
13
+ from pydantic import Field
14
+
15
+ from ..types import BaseModel
16
+
17
+
18
+
19
+ _CRYPTS = dict[str, 'CryptParams']
11
20
 
12
21
 
13
22
 
14
23
  class CryptParams(BaseModel, extra='forbid'):
15
24
  """
16
25
  Process and validate the core configuration parameters.
17
-
18
- :param phrase: Passphrases that are used in operations.
19
- :param data: Keyword arguments passed to Pydantic model.
20
- Parameter is picked up by autodoc, please ignore.
21
26
  """
22
27
 
23
- phrase: str
28
+ phrase: Annotated[
29
+ str,
30
+ Field(...,
31
+ description='Passphrase for the operations',
32
+ min_length=1)]
33
+
34
+
35
+ def __init__(
36
+ self,
37
+ phrase: str,
38
+ ) -> None:
39
+ """
40
+ Initialize instance for class using provided parameters.
41
+ """
42
+
43
+ super().__init__(**{
44
+ 'phrase': phrase})
24
45
 
25
46
 
26
47
 
27
48
  class CryptsParams(BaseModel, extra='forbid'):
28
49
  """
29
50
  Process and validate the core configuration parameters.
30
-
31
- :param phrases: Passphrases that are used in operations.
32
- :param data: Keyword arguments passed to Pydantic model.
33
- Parameter is picked up by autodoc, please ignore.
34
51
  """
35
52
 
36
- phrases: dict[str, CryptParams] = {}
53
+ phrases: Annotated[
54
+ _CRYPTS,
55
+ Field(...,
56
+ description='Passphrases for the operations',
57
+ min_length=0)]
58
+
59
+
60
+ def __init__(
61
+ self,
62
+ phrases: Optional[_CRYPTS] = None,
63
+ ) -> None:
64
+ """
65
+ Initialize instance for class using provided parameters.
66
+ """
67
+
68
+ phrases = phrases or {}
69
+
70
+ super().__init__(**{
71
+ 'phrases': phrases})
@@ -7,8 +7,6 @@ is permitted, for more information consult the project license file.
7
7
 
8
8
 
9
9
 
10
- from typing import Any
11
-
12
10
  from pytest import fixture
13
11
  from pytest import mark
14
12
  from pytest import raises
@@ -16,8 +14,10 @@ from pytest import raises
16
14
  from ..crypts import Crypts
17
15
  from ..params import CryptParams
18
16
  from ..params import CryptsParams
17
+ from ...types import DictStrAny
19
18
  from ...types import inrepr
20
19
  from ...types import instr
20
+ from ...types import lattrs
21
21
 
22
22
 
23
23
 
@@ -29,7 +29,7 @@ def crypts() -> Crypts:
29
29
  :returns: Newly constructed instance of related class.
30
30
  """
31
31
 
32
- source: dict[str, Any] = {
32
+ source: DictStrAny = {
33
33
  'default': {'phrase': Crypts.keygen()},
34
34
  'secrets': {'phrase': Crypts.keygen()}}
35
35
 
@@ -50,7 +50,7 @@ def test_Crypts(
50
50
  """
51
51
 
52
52
 
53
- attrs = list(crypts.__dict__)
53
+ attrs = lattrs(crypts)
54
54
 
55
55
  assert attrs == [
56
56
  '_Crypts__params']
@@ -67,7 +67,7 @@ def test_Crypts(
67
67
  crypts)
68
68
 
69
69
 
70
- assert crypts.params is not None
70
+ assert crypts.params
71
71
 
72
72
  assert len(crypts.keygen()) == 44
73
73
 
@@ -10,6 +10,7 @@ is permitted, for more information consult the project license file.
10
10
  from ..hashes import Hashes
11
11
  from ...types import inrepr
12
12
  from ...types import instr
13
+ from ...types import lattrs
13
14
 
14
15
 
15
16
 
@@ -21,7 +22,7 @@ def test_Hashes() -> None:
21
22
  hashes = Hashes('string')
22
23
 
23
24
 
24
- attrs = list(hashes.__dict__)
25
+ attrs = lattrs(hashes)
25
26
 
26
27
  assert attrs == [
27
28
  '_Hashes__string']
@@ -16,9 +16,10 @@ from .parse import parse_time
16
16
  from .parse import shift_time
17
17
  from .parse import since_time
18
18
  from .parse import string_time
19
+ from .time import Time
19
20
  from .timer import Timer
20
21
  from .timers import Timers
21
- from .times import Times
22
+ from .unitime import unitime
22
23
  from .utils import findtz
23
24
  from .window import Window
24
25
  from .windows import Windows
@@ -31,7 +32,7 @@ __all__ = [
31
32
  'TimerParams',
32
33
  'Timers',
33
34
  'TimersParams',
34
- 'Times',
35
+ 'Time',
35
36
  'Window',
36
37
  'WindowParams',
37
38
  'Windows',
@@ -40,4 +41,5 @@ __all__ = [
40
41
  'parse_time',
41
42
  'shift_time',
42
43
  'since_time',
43
- 'string_time']
44
+ 'string_time',
45
+ 'unitime']
encommon/times/common.py CHANGED
@@ -13,7 +13,7 @@ from typing import TYPE_CHECKING
13
13
  from typing import Union
14
14
 
15
15
  if TYPE_CHECKING:
16
- from .times import Times
16
+ from .time import Time
17
17
 
18
18
 
19
19
 
@@ -24,7 +24,8 @@ SNAPABLE = compile(
24
24
  r'^(\-|\+)[\d\@a-z\-\+]+$')
25
25
 
26
26
  STRINGNOW = {
27
- 'None', 'null', 'now'}
27
+ 'None', None,
28
+ 'null', 'now'}
28
29
 
29
30
 
30
31
 
@@ -32,7 +33,7 @@ NUMERIC = Union[int, float]
32
33
 
33
34
  PARSABLE = Union[
34
35
  str, NUMERIC,
35
- datetime, 'Times']
36
+ datetime, 'Time']
36
37
 
37
38
  SCHEDULE = Union[
38
39
  str, dict[str, int]]