omlish 0.0.0.dev302__py3-none-any.whl → 0.0.0.dev304__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.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev302'
2
- __revision__ = '0b4f820252a0f7a3e020da512ead1e112d150cd2'
1
+ __version__ = '0.0.0.dev304'
2
+ __revision__ = '0ecc67df99993947b491b2d6d6163fd00b00202e'
3
3
 
4
4
 
5
5
  #
@@ -35,7 +35,7 @@ from .base import SimpleBootstrap
35
35
 
36
36
 
37
37
  BOOTSTRAP_TYPES_BY_NAME: ta.Mapping[str, ta.Type[Bootstrap]] = { # noqa
38
- lang.snake_case(cls.__name__[:-len('Bootstrap')]): cls
38
+ lang.snake_case(*lang.split_string_casing(cls.__name__[:-len('Bootstrap')])): cls
39
39
  for cls in lang.deep_subclasses(Bootstrap, concrete_only=True)
40
40
  }
41
41
 
omlish/lang/__init__.py CHANGED
@@ -23,6 +23,33 @@ from .cached.property import ( # noqa
23
23
  cached_property,
24
24
  )
25
25
 
26
+ from .casing import ( # noqa
27
+ StringCasingError,
28
+ ImproperStringCasingError,
29
+ UnknownStringCasingError,
30
+ AmbiguousStringCasingError,
31
+
32
+ StringCasing,
33
+ CamelCase,
34
+ LowCamelCase,
35
+ SnakeCase,
36
+ UpSnakeCase,
37
+
38
+ STRING_CASINGS,
39
+ CAMEL_CASE,
40
+ LOW_CAMEL_CASE,
41
+ SNAKE_CASE,
42
+ UP_SNAKE_CASE,
43
+
44
+ camel_case,
45
+ low_camel_case,
46
+ snake_case,
47
+ up_snake_case,
48
+
49
+ get_string_casing,
50
+ split_string_casing,
51
+ )
52
+
26
53
  from .classes.abstract import ( # noqa
27
54
  Abstract,
28
55
  AbstractTypeError,
@@ -260,7 +287,6 @@ from .strings import ( # noqa
260
287
  BOOL_STRINGS,
261
288
  BOOL_TRUE_STRINGS,
262
289
  STRING_BOOL_VALUES,
263
- camel_case,
264
290
  find_any,
265
291
  indent_lines,
266
292
  is_dunder,
@@ -272,7 +298,6 @@ from .strings import ( # noqa
272
298
  prefix_lines,
273
299
  replace_many,
274
300
  rfind_any,
275
- snake_case,
276
301
  strip_prefix,
277
302
  strip_suffix,
278
303
  )
omlish/lang/casing.py ADDED
@@ -0,0 +1,192 @@
1
+ import abc
2
+ import re
3
+ import typing as ta
4
+
5
+
6
+ ##
7
+
8
+
9
+ class StringCasingError(Exception):
10
+ pass
11
+
12
+
13
+ class ImproperStringCasingError(StringCasingError):
14
+ pass
15
+
16
+
17
+ class UnknownStringCasingError(StringCasingError):
18
+ pass
19
+
20
+
21
+ class AmbiguousStringCasingError(StringCasingError):
22
+ pass
23
+
24
+
25
+ def _check_all_lowercase(*ps: str) -> None:
26
+ for p in ps:
27
+ if p.lower() != p:
28
+ raise ImproperStringCasingError(p)
29
+
30
+
31
+ ##
32
+
33
+
34
+ class StringCasing(abc.ABC):
35
+ @abc.abstractmethod
36
+ def match(self, s: str) -> bool:
37
+ raise NotImplementedError
38
+
39
+ @abc.abstractmethod
40
+ def split(self, s: str) -> list[str]:
41
+ """Returns lowercase."""
42
+
43
+ raise NotImplementedError
44
+
45
+ @abc.abstractmethod
46
+ def join(self, *parts: str) -> str:
47
+ """Expects lowercase."""
48
+
49
+ raise NotImplementedError
50
+
51
+
52
+ #
53
+
54
+
55
+ class CamelCase(StringCasing):
56
+ """FooBarBaz"""
57
+
58
+ _PAT: ta.ClassVar[re.Pattern] = re.compile(r'[A-Z][a-z0-9]*(?:[A-Z][a-z0-9]*)*')
59
+ _SPLIT_PAT: ta.ClassVar[re.Pattern] = re.compile(r'[A-Z][a-z0-9]*')
60
+
61
+ def match(self, s: str) -> bool:
62
+ return bool(self._PAT.fullmatch(s))
63
+
64
+ def split(self, s: str) -> list[str]:
65
+ if not self.match(s):
66
+ raise ImproperStringCasingError(f'Not valid CamelCase: {s!r}')
67
+ return [m.group(0).lower() for m in self._SPLIT_PAT.finditer(s)]
68
+
69
+ def join(self, *parts: str) -> str:
70
+ _check_all_lowercase(*parts)
71
+ return ''.join(p.capitalize() for p in parts)
72
+
73
+
74
+ #
75
+
76
+
77
+ class LowCamelCase(StringCasing):
78
+ """fooBarBaz"""
79
+
80
+ _MATCH_PAT: ta.ClassVar[re.Pattern] = re.compile(r'[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*')
81
+ _FIRST_PAT: ta.ClassVar[re.Pattern] = re.compile(r'^[a-z0-9]+')
82
+ _UPPER_PAT: ta.ClassVar[re.Pattern] = re.compile(r'[A-Z][a-z0-9]*')
83
+
84
+ def match(self, s: str) -> bool:
85
+ return bool(self._MATCH_PAT.fullmatch(s))
86
+
87
+ def split(self, s: str) -> list[str]:
88
+ if not self.match(s):
89
+ raise ImproperStringCasingError(f'Not valid lowCamelCase: {s!r}')
90
+ parts: list[str] = []
91
+ m0 = self._FIRST_PAT.match(s)
92
+ if m0:
93
+ parts.append(m0.group(0))
94
+ start = m0.end()
95
+ else:
96
+ start = 0
97
+ for m in self._UPPER_PAT.finditer(s, pos=start):
98
+ parts.append(m.group(0))
99
+ return [p.lower() for p in parts]
100
+
101
+ def join(self, *parts: str) -> str:
102
+ _check_all_lowercase(*parts)
103
+ if not parts:
104
+ return ''
105
+ first, *rest = parts
106
+ return first.lower() + ''.join(p.capitalize() for p in rest)
107
+
108
+
109
+ #
110
+
111
+
112
+ class SnakeCase(StringCasing):
113
+ """foo_bar_baz"""
114
+
115
+ _PAT: ta.ClassVar[re.Pattern] = re.compile(r'[a-z0-9]+(?:_[a-z0-9]+)*')
116
+
117
+ def match(self, s: str) -> bool:
118
+ return bool(self._PAT.fullmatch(s))
119
+
120
+ def split(self, s: str) -> list[str]:
121
+ if not self.match(s):
122
+ raise ImproperStringCasingError(f'Not valid snake_case: {s!r}')
123
+ return s.split('_')
124
+
125
+ def join(self, *parts: str) -> str:
126
+ _check_all_lowercase(*parts)
127
+ return '_'.join(p.lower() for p in parts)
128
+
129
+
130
+ #
131
+
132
+
133
+ class UpSnakeCase(StringCasing):
134
+ """FOO_BAR_BAZ"""
135
+
136
+ _PAT: ta.ClassVar[re.Pattern] = re.compile(r'[A-Z0-9]+(?:_[A-Z0-9]+)*')
137
+
138
+ def match(self, s: str) -> bool:
139
+ return bool(self._PAT.fullmatch(s))
140
+
141
+ def split(self, s: str) -> list[str]:
142
+ if not self.match(s):
143
+ raise ImproperStringCasingError(f'Not valid UPPER_SNAKE_CASE: {s!r}')
144
+ return [part.lower() for part in s.split('_')]
145
+
146
+ def join(self, *parts: str) -> str:
147
+ _check_all_lowercase(*parts)
148
+ return '_'.join(p.upper() for p in parts)
149
+
150
+
151
+ ##
152
+
153
+
154
+ STRING_CASINGS = [
155
+ (CAMEL_CASE := CamelCase()),
156
+ (LOW_CAMEL_CASE := LowCamelCase()),
157
+ (SNAKE_CASE := SnakeCase()),
158
+ (UP_SNAKE_CASE := UpSnakeCase()),
159
+ ]
160
+
161
+
162
+ camel_case = CAMEL_CASE.join
163
+ low_camel_case = LOW_CAMEL_CASE.join
164
+ snake_case = SNAKE_CASE.join
165
+ up_snake_case = UP_SNAKE_CASE.join
166
+
167
+
168
+ ##
169
+
170
+
171
+ def get_string_casing(s: str, casings: ta.Iterable[StringCasing] | None = None) -> StringCasing:
172
+ if casings is None:
173
+ casings = STRING_CASINGS
174
+ cs = [c for c in casings if c.match(s)]
175
+ if not cs:
176
+ raise UnknownStringCasingError
177
+ if len(cs) != 1:
178
+ raise AmbiguousStringCasingError
179
+ [c] = cs
180
+ return c
181
+
182
+
183
+ def split_string_casing(s: str, casings: ta.Iterable[StringCasing] | None = None) -> list[str]:
184
+ if casings is None:
185
+ casings = STRING_CASINGS
186
+ ts = {tuple(c.split(s)) for c in casings if c.match(s)}
187
+ if not ts:
188
+ raise UnknownStringCasingError
189
+ if len(ts) != 1:
190
+ raise AmbiguousStringCasingError
191
+ [t] = ts
192
+ return list(t)
omlish/lang/strings.py CHANGED
@@ -84,23 +84,6 @@ def rfind_any(
84
84
  ##
85
85
 
86
86
 
87
- def camel_case(name: str, *, lower: bool = False) -> str:
88
- if not name:
89
- return ''
90
- s = ''.join(map(str.capitalize, name.split('_'))) # noqa
91
- if lower:
92
- s = s[0].lower() + s[1:]
93
- return s
94
-
95
-
96
- def snake_case(name: str) -> str:
97
- uppers: list[int | None] = [i for i, c in enumerate(name) if c.isupper()]
98
- return '_'.join([name[l:r].lower() for l, r in zip([None, *uppers], [*uppers, None])]).strip('_')
99
-
100
-
101
- ##
102
-
103
-
104
87
  def is_dunder(name: str) -> bool:
105
88
  return (
106
89
  name[:2] == name[-2:] == '__' and
omlish/marshal/naming.py CHANGED
@@ -5,6 +5,7 @@ TODO:
5
5
  """
6
6
  import enum
7
7
 
8
+ from .. import check
8
9
  from .. import lang
9
10
  from .base import Option
10
11
 
@@ -16,11 +17,22 @@ class Naming(Option, enum.Enum):
16
17
 
17
18
 
18
19
  def translate_name(n: str, e: Naming) -> str:
20
+ check.non_empty_str(n)
21
+ check.not_equal(set(n), {'_'})
22
+
23
+ n1 = n.lstrip('_')
24
+ pfx = '_' * (len(n) - len(n1))
25
+ n2 = n1.rstrip('_')
26
+ sfx = '_' * (len(n1) - len(n2))
27
+ ps = lang.split_string_casing(n2)
28
+
19
29
  if e is Naming.SNAKE:
20
- return lang.snake_case(n)
21
- if e is Naming.CAMEL:
22
- return lang.camel_case(n)
23
- if e is Naming.LOW_CAMEL:
24
- r = lang.camel_case(n)
25
- return (r[0].lower() + r[1:]) if r else r
26
- raise ValueError(e)
30
+ r = lang.snake_case(*ps)
31
+ elif e is Naming.CAMEL:
32
+ r = lang.camel_case(*ps)
33
+ elif e is Naming.LOW_CAMEL:
34
+ r = lang.low_camel_case(*ps)
35
+ else:
36
+ raise ValueError(e)
37
+
38
+ return pfx + r + sfx
@@ -104,7 +104,7 @@ def _is_actual_number(x: ta.Any) -> bool:
104
104
 
105
105
 
106
106
  def node_type(n: Node) -> str:
107
- return lang.snake_case(type(n).__name__)
107
+ return lang.snake_case(*lang.split_string_casing(type(n).__name__))
108
108
 
109
109
 
110
110
  ##
@@ -44,6 +44,10 @@ from .keywords.unknown import ( # noqa
44
44
  )
45
45
 
46
46
  from .keywords.validation import ( # noqa
47
+ AdditionalProperties,
48
+ AnyOf,
49
+ Const,
50
+ Enum,
47
51
  ExclusiveMaximum,
48
52
  ExclusiveMinimum,
49
53
  Items,
@@ -51,6 +55,7 @@ from .keywords.validation import ( # noqa
51
55
  Maximum,
52
56
  MinItems,
53
57
  Minimum,
58
+ OneOf,
54
59
  Properties,
55
60
  Required,
56
61
  Type,
@@ -75,6 +75,16 @@ class Keywords(lang.Final):
75
75
  ##
76
76
 
77
77
 
78
+ @dc.dataclass(frozen=True)
79
+ class AnyKeyword(Keyword, lang.Abstract):
80
+ v: ta.Any
81
+
82
+
83
+ @dc.dataclass(frozen=True)
84
+ class AnyArrayKeyword(Keyword, lang.Abstract):
85
+ vs: ta.Sequence[ta.Any]
86
+
87
+
78
88
  @dc.dataclass(frozen=True)
79
89
  class BooleanKeyword(Keyword, lang.Abstract):
80
90
  b: bool
@@ -91,7 +101,7 @@ class StrKeyword(Keyword, lang.Abstract):
91
101
 
92
102
 
93
103
  @dc.dataclass(frozen=True)
94
- class StrOrStrsKeyword(Keyword, lang.Abstract):
104
+ class StrOrStrArrayKeyword(Keyword, lang.Abstract):
95
105
  ss: str | ta.Sequence[str]
96
106
 
97
107
 
@@ -100,6 +110,16 @@ class KeywordsKeyword(Keyword, lang.Abstract):
100
110
  kw: Keywords
101
111
 
102
112
 
113
+ @dc.dataclass(frozen=True)
114
+ class KeywordsArrayKeyword(Keyword, lang.Abstract):
115
+ kws: ta.Sequence[Keywords]
116
+
117
+
103
118
  @dc.dataclass(frozen=True)
104
119
  class StrToKeywordsKeyword(Keyword, lang.Abstract):
105
120
  m: ta.Mapping[str, Keywords]
121
+
122
+
123
+ @dc.dataclass(frozen=True)
124
+ class BooleanOrKeywordsKeyword(Keyword, lang.Abstract):
125
+ bk: bool | Keywords
@@ -3,14 +3,18 @@ import typing as ta
3
3
  from .... import check
4
4
  from .... import collections as col
5
5
  from .... import lang
6
+ from .base import AnyArrayKeyword
7
+ from .base import AnyKeyword
6
8
  from .base import BooleanKeyword
9
+ from .base import BooleanOrKeywordsKeyword
7
10
  from .base import Keyword
8
11
  from .base import Keywords
12
+ from .base import KeywordsArrayKeyword
9
13
  from .base import KeywordsKeyword
10
14
  from .base import KnownKeyword
11
15
  from .base import NumberKeyword
12
16
  from .base import StrKeyword
13
- from .base import StrOrStrsKeyword
17
+ from .base import StrOrStrArrayKeyword
14
18
  from .base import StrToKeywordsKeyword
15
19
  from .core import CoreKeyword
16
20
  from .format import FormatKeyword
@@ -69,16 +73,28 @@ class KeywordParser:
69
73
  self._allow_unknown = allow_unknown
70
74
 
71
75
  def parse_keyword(self, cls: type[KeywordT], v: ta.Any) -> KeywordT:
72
- if issubclass(cls, BooleanKeyword):
76
+ if issubclass(cls, AnyKeyword):
77
+ return cls(v) # type: ignore
78
+
79
+ elif issubclass(cls, AnyArrayKeyword):
80
+ return cls(tuple(check.isinstance(v, ta.Sequence))) # type: ignore
81
+
82
+ elif issubclass(cls, BooleanKeyword):
73
83
  return cls(check.isinstance(v, bool)) # type: ignore
74
84
 
85
+ elif issubclass(cls, BooleanOrKeywordsKeyword):
86
+ if isinstance(v, bool):
87
+ return cls(v) # type: ignore
88
+ else:
89
+ return cls(self.parse_keywords(v)) # type: ignore
90
+
75
91
  elif issubclass(cls, NumberKeyword):
76
92
  return cls(check.isinstance(v, (int, float))) # type: ignore
77
93
 
78
94
  elif issubclass(cls, StrKeyword):
79
95
  return cls(check.isinstance(v, str)) # type: ignore
80
96
 
81
- elif issubclass(cls, StrOrStrsKeyword):
97
+ elif issubclass(cls, StrOrStrArrayKeyword):
82
98
  ss: str | ta.Sequence[str]
83
99
  if isinstance(v, str):
84
100
  ss = v
@@ -91,6 +107,9 @@ class KeywordParser:
91
107
  elif issubclass(cls, KeywordsKeyword):
92
108
  return cls(self.parse_keywords(v)) # type: ignore
93
109
 
110
+ elif issubclass(cls, KeywordsArrayKeyword):
111
+ return cls(tuple(self.parse_keywords(e) for e in v)) # type: ignore
112
+
94
113
  elif issubclass(cls, StrToKeywordsKeyword):
95
114
  return cls({k: self.parse_keywords(mv) for k, mv in v.items()}) # type: ignore
96
115
 
@@ -1,12 +1,16 @@
1
1
  import typing as ta
2
2
 
3
+ from .base import AnyArrayKeyword
4
+ from .base import AnyKeyword
3
5
  from .base import BooleanKeyword
6
+ from .base import BooleanOrKeywordsKeyword
4
7
  from .base import Keyword
5
8
  from .base import Keywords
9
+ from .base import KeywordsArrayKeyword
6
10
  from .base import KeywordsKeyword
7
11
  from .base import NumberKeyword
8
12
  from .base import StrKeyword
9
- from .base import StrOrStrsKeyword
13
+ from .base import StrOrStrArrayKeyword
10
14
  from .base import StrToKeywordsKeyword
11
15
  from .unknown import UnknownKeyword
12
16
 
@@ -15,16 +19,28 @@ from .unknown import UnknownKeyword
15
19
 
16
20
 
17
21
  def render_keyword(kw: Keyword) -> dict[str, ta.Any]:
18
- if isinstance(kw, BooleanKeyword):
22
+ if isinstance(kw, AnyKeyword):
23
+ return {kw.tag: kw.v}
24
+
25
+ elif isinstance(kw, AnyArrayKeyword):
26
+ return {kw.tag: kw.vs}
27
+
28
+ elif isinstance(kw, BooleanKeyword):
19
29
  return {kw.tag: kw.b}
20
30
 
31
+ elif isinstance(kw, BooleanOrKeywordsKeyword):
32
+ if isinstance(kw.bk, bool):
33
+ return {kw.tag: kw.bk}
34
+ else:
35
+ return {kw.tag: render_keywords(kw.bk)}
36
+
21
37
  elif isinstance(kw, NumberKeyword):
22
38
  return {kw.tag: kw.n}
23
39
 
24
40
  elif isinstance(kw, StrKeyword):
25
41
  return {kw.tag: kw.s}
26
42
 
27
- elif isinstance(kw, StrOrStrsKeyword):
43
+ elif isinstance(kw, StrOrStrArrayKeyword):
28
44
  if isinstance(kw.ss, str):
29
45
  return {kw.tag: kw.ss}
30
46
  else:
@@ -33,6 +49,9 @@ def render_keyword(kw: Keyword) -> dict[str, ta.Any]:
33
49
  elif isinstance(kw, KeywordsKeyword):
34
50
  return {kw.tag: render_keywords(kw.kw)}
35
51
 
52
+ elif isinstance(kw, KeywordsArrayKeyword):
53
+ return {kw.tag: [render_keywords(c) for c in kw.kws]}
54
+
36
55
  elif isinstance(kw, StrToKeywordsKeyword):
37
56
  return {kw.tag: {k: render_keywords(v) for k, v in kw.m.items()}}
38
57
 
@@ -1,9 +1,13 @@
1
1
  from .... import lang
2
+ from .base import AnyArrayKeyword
3
+ from .base import AnyKeyword
2
4
  from .base import BooleanKeyword
5
+ from .base import BooleanOrKeywordsKeyword
6
+ from .base import KeywordsArrayKeyword
3
7
  from .base import KeywordsKeyword
4
8
  from .base import KnownKeyword
5
9
  from .base import NumberKeyword
6
- from .base import StrOrStrsKeyword
10
+ from .base import StrOrStrArrayKeyword
7
11
  from .base import StrToKeywordsKeyword
8
12
 
9
13
 
@@ -17,7 +21,15 @@ class ValidationKeyword(KnownKeyword, lang.Abstract, lang.Sealed):
17
21
  ##
18
22
 
19
23
 
20
- class Type(StrOrStrsKeyword, ValidationKeyword, lang.Final, tag='type'):
24
+ class Type(StrOrStrArrayKeyword, ValidationKeyword, lang.Final, tag='type'):
25
+ pass
26
+
27
+
28
+ class Const(AnyKeyword, ValidationKeyword, lang.Final, tag='const'):
29
+ pass
30
+
31
+
32
+ class Enum(AnyArrayKeyword, ValidationKeyword, lang.Final, tag='enum'):
21
33
  pass
22
34
 
23
35
 
@@ -25,7 +37,7 @@ class Items(KeywordsKeyword, ValidationKeyword, lang.Final, tag='items'):
25
37
  pass
26
38
 
27
39
 
28
- class Required(StrOrStrsKeyword, ValidationKeyword, lang.Final, tag='required'):
40
+ class Required(StrOrStrArrayKeyword, ValidationKeyword, lang.Final, tag='required'):
29
41
  pass
30
42
 
31
43
 
@@ -33,6 +45,10 @@ class Properties(StrToKeywordsKeyword, ValidationKeyword, lang.Final, tag='prope
33
45
  pass
34
46
 
35
47
 
48
+ class AdditionalProperties(BooleanOrKeywordsKeyword, ValidationKeyword, lang.Final, tag='additionalProperties'):
49
+ pass
50
+
51
+
36
52
  ##
37
53
 
38
54
 
@@ -65,3 +81,14 @@ class Minimum(NumberKeyword, ValidationKeyword, lang.Final, tag='minimum'):
65
81
 
66
82
  class ExclusiveMinimum(NumberKeyword, ValidationKeyword, lang.Final, tag='exclusiveMinimum'):
67
83
  pass
84
+
85
+
86
+ #
87
+
88
+
89
+ class AnyOf(KeywordsArrayKeyword, ValidationKeyword, lang.Final, tag='anyOf'):
90
+ pass
91
+
92
+
93
+ class OneOf(KeywordsArrayKeyword, ValidationKeyword, lang.Final, tag='oneOf'):
94
+ pass
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2022 JSON Schema Specification Authors
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
+ following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
+ disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
10
+ disclaimer in the documentation and/or other materials provided with the distribution.
11
+
12
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev302
3
+ Version: 0.0.0.dev304
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=pjGUyLHaoWpPqRP3jz2u1fC1qoRc2lvrEcpU_Ax2tdg,8253
2
- omlish/__about__.py,sha256=VEC7wFGaSoAMF2E62PWgQVju9B2RuX6O49UlGrjLBRo,3478
2
+ omlish/__about__.py,sha256=F6X4fib8qJRwj4c8ttKlheoGULweTMxejclgu8k0w64,3478
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -132,7 +132,7 @@ omlish/bootstrap/__init__.py,sha256=-Rtsg7uPQNhh1dIT9nqrz96XlqizwoLnWf-FwOEstJI,
132
132
  omlish/bootstrap/__main__.py,sha256=4jCwsaogp0FrJjJZ85hzF4-WqluPeheHbfeoKynKvNs,194
133
133
  omlish/bootstrap/base.py,sha256=d8hqn4hp1XMMi5PgcJBQXPKmW47epu8CxBlqDZiRZb4,1073
134
134
  omlish/bootstrap/diag.py,sha256=iemH0nQEHEDzyZztvd_ygGGVpRpgn5UG6naxeQTvXp0,5347
135
- omlish/bootstrap/harness.py,sha256=VW8YP-yENGyXIuJ8GL_xintArF13nafwpz-iAghPt34,1967
135
+ omlish/bootstrap/harness.py,sha256=BMFNTYG03V74WFW5zd6aaxIb6uzGeldiR3VX2alQwlU,1994
136
136
  omlish/bootstrap/main.py,sha256=yZhOHDDlj4xB5a89dRdT8z58FsqqnpoBg1-tvY2CJe4,5903
137
137
  omlish/bootstrap/marshal.py,sha256=mH6KVQILEG7Qb_mULNRe8DGDSZb99mQr9jve4mhqUfc,481
138
138
  omlish/bootstrap/sys.py,sha256=0F0uThMsYdjqUtzrYHr4Xsh_MjscxgWl149i_3tDOqo,8787
@@ -464,8 +464,9 @@ omlish/iterators/iterators.py,sha256=RxW35yQ5ed8vBQ22IqpDXFx-i5JiLQdp7-pkMZXhJJ8
464
464
  omlish/iterators/recipes.py,sha256=wOwOZg-zWG9Zc3wcAxJFSe2rtavVBYwZOfG09qYEx_4,472
465
465
  omlish/iterators/tools.py,sha256=c4hArZEVV8y9_dFfmRwakusv1cWJLT4MkTkGRjnGN5U,2556
466
466
  omlish/iterators/unique.py,sha256=Nw0pSaNEcHAkve0ugfLPvJcirDOn9ECyC5wIL8JlJKI,1395
467
- omlish/lang/__init__.py,sha256=KCzbT9IMWi2TNldAlDZ6b8Rr-7hyV9Ne6kIKJLXNAxg,5315
467
+ omlish/lang/__init__.py,sha256=1m2Kc4CBk_C_B7ydPcGWTdCY00JRMrGtX_RlFvyVTo8,5729
468
468
  omlish/lang/attrs.py,sha256=i7euRF81uNF8QDmUVXSK_BtqLGshaMi4VVdUnMjiMwg,5050
469
+ omlish/lang/casing.py,sha256=cFUlbDdXLhwnWwcYx4qnM5c4zGX7hIRUfcjiZbxUD28,4636
469
470
  omlish/lang/clsdct.py,sha256=HAGIvBSbCefzRjXriwYSBLO7QHKRv2UsE78jixOb-fA,1828
470
471
  omlish/lang/collections.py,sha256=LVm0Sory60IXyFzYhhO8BZAWy_z_pjiA-meXNlSJP7o,2465
471
472
  omlish/lang/comparison.py,sha256=MOwEG0Yny-jBPHO9kQto9FSRyeNpQW24UABsghkrHxY,1356
@@ -483,7 +484,7 @@ omlish/lang/outcomes.py,sha256=mpFy_VoM-b74L1aCFsjsZVUHx_icZ1AHMOKeVesjOp4,8628
483
484
  omlish/lang/params.py,sha256=QmNVBfJsfxjDG5ilDPgHV7sK4UwRztkSQdLTo0umb8I,6648
484
485
  omlish/lang/resolving.py,sha256=ei9LDyJexsMMHB9z8diUkNmynWhd_da7h7TqrMYM6lA,1611
485
486
  omlish/lang/resources.py,sha256=WKkAddC3ctMK1bvGw-elGe8ZxAj2IaUTKVSu2nfgHTo,2839
486
- omlish/lang/strings.py,sha256=egdv8PxLNG40-5V93agP5j2rBUDIsahCx048zV7uEbU,4690
487
+ omlish/lang/strings.py,sha256=kJmRFd1D36xXcjd9MdB12BCwF_-MVhNr-TpWj7hMi_4,4252
487
488
  omlish/lang/sys.py,sha256=b4qOPiJZQru_mbb04FNfOjYWUxlV2becZOoc-yya_rQ,411
488
489
  omlish/lang/typing.py,sha256=Zdad9Zv0sa-hIaUXPrzPidT7sDVpRcussAI7D-j-I1c,3296
489
490
  omlish/lang/cached/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -550,7 +551,7 @@ omlish/marshal/base.py,sha256=Q0ZRsz5z0NTI6PeWPc9mdMstJryDDbeIAdpKH9-SDps,11427
550
551
  omlish/marshal/errors.py,sha256=g5XJyTHd__8lfwQ4KwgK-E5WR6MoNTMrqKP2U_QRQQQ,307
551
552
  omlish/marshal/factories.py,sha256=Q926jSVjaQLEmStnHLhm_c_vqEysN1LnDCwAsFLIzXw,2970
552
553
  omlish/marshal/global_.py,sha256=sdBC6PbP77iUAYZ9GIYyAFrbmg14bp6iU3f1l5tpOSE,1378
553
- omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
554
+ omlish/marshal/naming.py,sha256=7jQ204u_Kpc3-OGr-ctUHSv997DdWYRLh643qLHJhks,852
554
555
  omlish/marshal/proxy.py,sha256=puKJpwPpuDlMOIrKMcLTRLJyMiL6n_Xs-p59AuDEymA,543
555
556
  omlish/marshal/registries.py,sha256=FvC6qXHCizNB2QmU_N3orxW7iqfGYkiUXYYdTRWS6HA,2353
556
557
  omlish/marshal/standard.py,sha256=TADR75Hd9VSUpuN_Tnu74Bzmvby42P2bzwFwUBC0l-Q,4283
@@ -679,22 +680,23 @@ omlish/specs/jmespath/functions.py,sha256=YnuwlgkcbUJWlqOvSpN3LGXZpF0fpImKa--FLk
679
680
  omlish/specs/jmespath/lexer.py,sha256=WGxkwQe_dcHWcJcGg9q6K-8_Q0oRdWkw09dYGFNTHbk,12639
680
681
  omlish/specs/jmespath/parser.py,sha256=yfkydotVR4LBhrUTsptL_kLYDoGZrRN9zSEs_76kvZM,24441
681
682
  omlish/specs/jmespath/scope.py,sha256=UyDsl9rv_c8DCjJBuVIA2ESu1jrgYvuwEKiaJDQKnT0,1590
682
- omlish/specs/jmespath/visitor.py,sha256=4jCK_WDf7mBwxAZY2AKAcLOJICQZCSL7Gny8-IplicA,16565
683
+ omlish/specs/jmespath/visitor.py,sha256=HVro_6aBGL0CMBy8NRy6vJzWgwsHGB1qJXldX8H7wSg,16592
683
684
  omlish/specs/jsonrpc/__init__.py,sha256=QQwr-jkgvwr1ZMlNwl5W1TuHcxx8RuzQVFwWwNhp5sM,515
684
685
  omlish/specs/jsonrpc/errors.py,sha256=-Zgmlo6bV6J8w5f8h9axQgLquIFBHDgIwcpufEH5NsE,707
685
686
  omlish/specs/jsonrpc/marshal.py,sha256=HM736piPGnBZrg8CMLDX-L5fZpegyF6l6JUjzLoSDtk,1852
686
687
  omlish/specs/jsonrpc/types.py,sha256=emEiTPWsjsYy0jCC3It1bUEcu9nHp5y7-j73U1D6vl4,2700
687
- omlish/specs/jsonschema/__init__.py,sha256=qmlpJJlB9TBwvE2qCjRHeecNhEYonpbncXfX0T2L-do,1060
688
+ omlish/specs/jsonschema/__init__.py,sha256=55P7Yg2MprqDyaifac2ExNzK6blTZuDP4ejrUXZWpt8,1129
688
689
  omlish/specs/jsonschema/types.py,sha256=_H7ma99hD3_Xu42BFGHOXRI5p79tY8WBX8QE36k7lbw,472
689
690
  omlish/specs/jsonschema/keywords/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
690
- omlish/specs/jsonschema/keywords/base.py,sha256=jbLzU5_MeLcVrsbPlF2HPt0X0MldyOQmofZxelNTwP4,2416
691
+ omlish/specs/jsonschema/keywords/base.py,sha256=KYxKDxZtJGykLcJPTPvDMPDbbmuUw6RLOGgpCNkFcww,2830
691
692
  omlish/specs/jsonschema/keywords/core.py,sha256=3Pbi8d-eocEAxEdemNa0ldp5lrLWNmH0Tye-5rglUoU,535
692
693
  omlish/specs/jsonschema/keywords/format.py,sha256=9trrxHe38FDx47I8UfvO4PD_IygRlkEyTUJ3XlxDM6Y,244
693
694
  omlish/specs/jsonschema/keywords/metadata.py,sha256=IVWQKWT9xi0R07pXc79ErT7RBu5b6Kzg4pWYIITIRbs,336
694
- omlish/specs/jsonschema/keywords/parse.py,sha256=zWSOhHHzXbj-Yn5owU_w0V5w8yhiW4qqc4c7lMvavk0,3690
695
- omlish/specs/jsonschema/keywords/render.py,sha256=kHlBwNjSvKtca0IXBP5DWDRW-H6MduO6PZjhkBFRImU,1353
695
+ omlish/specs/jsonschema/keywords/parse.py,sha256=8lx17ZoaMF0u0NyAIVM9EmZD6gYLANlw0-zr9DN2HTA,4414
696
+ omlish/specs/jsonschema/keywords/render.py,sha256=wZ9yvfscnW8fYlQTXzmJjMYTKhSTg9hjrtlAEwMRaMQ,1947
696
697
  omlish/specs/jsonschema/keywords/unknown.py,sha256=iYIQlBbLUqISvTvj_Kup4wVDRxcEwmnLTyAAWjlxsck,234
697
- omlish/specs/jsonschema/keywords/validation.py,sha256=RJdGAsl_FtUmw1Bin_mrJ5qhN06rBC3f_L-rCBYdIOc,1342
698
+ omlish/specs/jsonschema/keywords/validation.py,sha256=bKu1bDOms5zxg5Xme1ki_jb7TYDFEOv_JKOzeYbxuYQ,1970
699
+ omlish/specs/jsonschema/schemas/LICENSE,sha256=CU2AUO-rKNc9s9vngzyGxUMgaZ0Aevr8lgN2DFFFxKw,1491
698
700
  omlish/specs/jsonschema/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
699
701
  omlish/specs/jsonschema/schemas/draft202012/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
700
702
  omlish/specs/jsonschema/schemas/draft202012/metaschema.json,sha256=Qdp29a-3zgYtJI92JGOpL3ykfk4PkFsiS6av7vkd7Q8,2452
@@ -843,9 +845,9 @@ omlish/typedvalues/holder.py,sha256=ZTnHiw-K38ciOBLEdwgrltr7Xp8jjEs_0Lp69DH-G-o,
843
845
  omlish/typedvalues/marshal.py,sha256=hWHRLcrGav7lvXJDtb9bNI0ickl4SKPQ6F4BbTpqw3A,4219
844
846
  omlish/typedvalues/reflect.py,sha256=Ih1YgU-srUjsvBn_P7C66f73_VCvcwqE3ffeBnZBgt4,674
845
847
  omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
846
- omlish-0.0.0.dev302.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
847
- omlish-0.0.0.dev302.dist-info/METADATA,sha256=ARPvC1-WLWPuw1QpgF2xijl-9JRU8BHBzFVsFadjAfg,4416
848
- omlish-0.0.0.dev302.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
849
- omlish-0.0.0.dev302.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
850
- omlish-0.0.0.dev302.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
851
- omlish-0.0.0.dev302.dist-info/RECORD,,
848
+ omlish-0.0.0.dev304.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
849
+ omlish-0.0.0.dev304.dist-info/METADATA,sha256=pBvxWE8MwSuga9H9NPi6L6YuxZ-EuSu4jYXGAn36N0Q,4416
850
+ omlish-0.0.0.dev304.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
851
+ omlish-0.0.0.dev304.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
852
+ omlish-0.0.0.dev304.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
853
+ omlish-0.0.0.dev304.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.0.0)
2
+ Generator: setuptools (80.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5