omextra 0.0.0.dev472__py3-none-any.whl → 0.0.0.dev473__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.
@@ -0,0 +1,345 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import dataclasses as dc
5
+ from omlish import lang
6
+
7
+ from .base import Match
8
+ from .base import Parser
9
+ from .base import _Context
10
+
11
+
12
+ ##
13
+
14
+
15
+ class Literal(Parser, lang.Abstract):
16
+ def _match_repr(self) -> str:
17
+ return repr(self)
18
+
19
+
20
+ class StringLiteral(Literal):
21
+ def __init__(self, value: str) -> None:
22
+ super().__init__()
23
+
24
+ self._value = check.non_empty_str(value)
25
+
26
+ @property
27
+ def value(self) -> str:
28
+ return self._value
29
+
30
+ def __repr__(self) -> str:
31
+ return f'{self.__class__.__name__}@{id(self):x}({self._value!r})'
32
+
33
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
34
+ if start < len(ctx._source): # noqa
35
+ source = ctx._source[start : start + len(self._value)] # noqa
36
+ if source == self._value:
37
+ yield Match(self, start, start + len(source), ())
38
+
39
+
40
+ class CaseInsensitiveStringLiteral(Literal):
41
+ def __init__(self, value: str) -> None:
42
+ super().__init__()
43
+
44
+ self._value = check.non_empty_str(value).casefold()
45
+
46
+ @property
47
+ def value(self) -> str:
48
+ return self._value
49
+
50
+ def __repr__(self) -> str:
51
+ return f'{self.__class__.__name__}@{id(self):x}({self._value!r})'
52
+
53
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
54
+ if start < len(ctx._source): # noqa
55
+ source = ctx._source[start : start + len(self._value)].casefold() # noqa
56
+ if source == self._value:
57
+ yield Match(self, start, start + len(source), ())
58
+
59
+
60
+ class RangeLiteral(Literal):
61
+ @dc.dataclass(frozen=True)
62
+ class Range:
63
+ lo: str
64
+ hi: str
65
+
66
+ def __post_init__(self) -> None:
67
+ check.non_empty_str(self.lo)
68
+ check.non_empty_str(self.hi)
69
+ check.state(self.hi >= self.lo)
70
+
71
+ def __init__(self, value: Range) -> None:
72
+ super().__init__()
73
+
74
+ self._value = check.isinstance(value, RangeLiteral.Range)
75
+
76
+ @property
77
+ def value(self) -> Range:
78
+ return self._value
79
+
80
+ def __repr__(self) -> str:
81
+ return f'{self.__class__.__name__}@{id(self):x}({self._value!r})'
82
+
83
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
84
+ try:
85
+ source = ctx._source[start] # noqa
86
+ except IndexError:
87
+ return
88
+ # ranges are always case-sensitive
89
+ if (value := self._value).lo <= source <= value.hi:
90
+ yield Match(self, start, start + 1, ())
91
+
92
+
93
+ @ta.overload
94
+ def literal(s: str, *, case_sensitive: bool = False) -> StringLiteral:
95
+ ...
96
+
97
+
98
+ @ta.overload
99
+ def literal(lo: str, hi: str) -> RangeLiteral:
100
+ ...
101
+
102
+
103
+ def literal(*args, case_sensitive=None):
104
+ if not args:
105
+ raise TypeError
106
+ elif len(args) == 1:
107
+ s = check.isinstance(check.single(args), str)
108
+ if case_sensitive:
109
+ return StringLiteral(s)
110
+ else:
111
+ return CaseInsensitiveStringLiteral(s)
112
+ elif len(args) == 2:
113
+ check.none(case_sensitive)
114
+ return RangeLiteral(RangeLiteral.Range(*map(check.of_isinstance(str), args)))
115
+ else:
116
+ raise TypeError(args)
117
+
118
+
119
+ ##
120
+
121
+
122
+ class Concat(Parser):
123
+ def __init__(self, *children: Parser) -> None:
124
+ super().__init__()
125
+
126
+ for c in check.not_empty(children):
127
+ check.isinstance(c, Parser)
128
+ self._children = children
129
+
130
+ @property
131
+ def children(self) -> ta.Sequence[Parser]:
132
+ return self._children
133
+
134
+ def __repr__(self) -> str:
135
+ return f'{self.__class__.__name__}@{id(self):x}({", ".join(map(repr, self._children))})'
136
+
137
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
138
+ i = 0
139
+ match_tups: list[tuple[Match, ...]] = [()]
140
+ for cp in self._children:
141
+ next_match_tups: list[tuple[Match, ...]] = []
142
+ for mt in match_tups:
143
+ for cm in ctx.iter_parse(cp, mt[-1].end if mt else start):
144
+ next_match_tups.append((*mt, cm))
145
+ i += 1
146
+ if not next_match_tups:
147
+ return
148
+ match_tups = next_match_tups
149
+ if not i:
150
+ return
151
+ for mt in sorted(match_tups, key=len, reverse=True):
152
+ yield Match(self, start, mt[-1].end if mt else start, mt)
153
+
154
+
155
+ concat = Concat
156
+
157
+
158
+ ##
159
+
160
+
161
+ class Repeat(Parser):
162
+ @dc.dataclass(frozen=True)
163
+ class Times:
164
+ min: int = 0
165
+ max: int | None = None
166
+
167
+ def __post_init__(self) -> None:
168
+ if self.max is not None:
169
+ check.state(self.max >= self.min)
170
+
171
+ def __repr__(self) -> str:
172
+ return f'{self.__class__.__name__}({self.min}{f", {self.max!r}" if self.max is not None else ""})'
173
+
174
+ def __init__(self, times: Times, child: Parser) -> None:
175
+ super().__init__()
176
+
177
+ self._times = check.isinstance(times, Repeat.Times)
178
+ self._child = check.isinstance(child, Parser)
179
+
180
+ @property
181
+ def times(self) -> Times:
182
+ return self._times
183
+
184
+ @property
185
+ def child(self) -> Parser:
186
+ return self._child
187
+
188
+ def __repr__(self) -> str:
189
+ return f'{self.__class__.__name__}@{id(self):x}({self._times}, {self._child!r})'
190
+
191
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
192
+ match_tup_set: set[tuple[Match, ...]] = set()
193
+ last_match_tup_set: set[tuple[Match, ...]] = {()}
194
+ i = 0
195
+ while True:
196
+ if self._times.max is not None and i == self._times.max:
197
+ break
198
+ next_match_tup_set: set[tuple[Match, ...]] = set()
199
+ for mt in last_match_tup_set:
200
+ for cm in ctx.iter_parse(self._child, mt[-1].end if mt else start):
201
+ next_match_tup_set.add((*mt, cm))
202
+ if not next_match_tup_set or next_match_tup_set < match_tup_set:
203
+ break
204
+ i += 1
205
+ match_tup_set |= next_match_tup_set
206
+ last_match_tup_set = next_match_tup_set
207
+ if i < self._times.min:
208
+ return
209
+ for mt in sorted(match_tup_set or [()], key=len, reverse=True):
210
+ yield Match(self, start, mt[-1].end if mt else start, mt) # noqa
211
+
212
+
213
+ class Option(Repeat):
214
+ def __init__(self, child: Parser) -> None:
215
+ super().__init__(Repeat.Times(0, 1), child)
216
+
217
+ def __repr__(self) -> str:
218
+ return f'{self.__class__.__name__}@{id(self):x}({self._child!r})'
219
+
220
+
221
+ option = Option
222
+
223
+
224
+ @ta.overload
225
+ def repeat(child: Parser) -> Repeat: # noqa
226
+ ...
227
+
228
+
229
+ @ta.overload
230
+ def repeat(times: Repeat.Times, child: Parser) -> Repeat: # noqa
231
+ ...
232
+
233
+
234
+ @ta.overload
235
+ def repeat(min: int, child: Parser) -> Repeat: # noqa
236
+ ...
237
+
238
+
239
+ @ta.overload
240
+ def repeat(min: int, max: int | None, child: Parser) -> Repeat: # noqa
241
+ ...
242
+
243
+
244
+ def repeat(*args):
245
+ # !!! FIXME: boneheaded args, repeat(1, c) currently means 1-*, should be exactly 1-1, should explicitly pass
246
+ # None for *
247
+ min: int # noqa
248
+ max: int | None # noqa
249
+
250
+ if len(args) < 2:
251
+ [child] = args
252
+ min, max = 0, None # noqa
253
+
254
+ elif len(args) > 2:
255
+ min, max, child = args # noqa
256
+
257
+ else:
258
+ ti, child = args # noqa
259
+
260
+ if isinstance(ti, Repeat.Times):
261
+ min, max = ti.min, ti.max # noqa
262
+
263
+ else:
264
+ min, max = ti, None # noqa
265
+
266
+ if (min, max) == (0, 1):
267
+ return Option(check.isinstance(child, Parser))
268
+
269
+ else:
270
+ return Repeat(
271
+ Repeat.Times(
272
+ check.isinstance(min, int),
273
+ check.isinstance(max, (int, None)),
274
+ ),
275
+ check.isinstance(child, Parser),
276
+ )
277
+
278
+
279
+ ##
280
+
281
+
282
+ class Either(Parser):
283
+ def __init__(self, *children: Parser, first_match: bool = False) -> None:
284
+ super().__init__()
285
+
286
+ for c in check.not_empty(children):
287
+ check.isinstance(c, Parser)
288
+ self._children = children
289
+ self._first_match = first_match
290
+
291
+ @property
292
+ def children(self) -> ta.Sequence[Parser]:
293
+ return self._children
294
+
295
+ @property
296
+ def first_match(self) -> bool:
297
+ return self._first_match
298
+
299
+ def __repr__(self) -> str:
300
+ return (
301
+ f'{self.__class__.__name__}@{id(self):x}('
302
+ f'{", ".join(map(repr, self._children))}'
303
+ f'{", first_match=True" if self._first_match else ""})'
304
+ )
305
+
306
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
307
+ for cp in self._children:
308
+ found = False
309
+ for cm in ctx.iter_parse(cp, start):
310
+ found = True
311
+ yield Match(self, start, cm.end, (cm,))
312
+ if found and self._first_match:
313
+ return
314
+
315
+
316
+ either = Either
317
+
318
+
319
+ ##
320
+
321
+
322
+ class RuleRef(Parser):
323
+ def __init__(self, name: str) -> None:
324
+ super().__init__()
325
+
326
+ self._name = check.non_empty_str(name)
327
+ self._name_f = name.casefold()
328
+
329
+ @property
330
+ def name(self) -> str:
331
+ return self._name
332
+
333
+ def __repr__(self) -> str:
334
+ return f'{self.__class__.__name__}@{id(self):x}({self._name!r})'
335
+
336
+ def _match_repr(self) -> str:
337
+ return repr(self)
338
+
339
+ def _iter_parse(self, ctx: _Context, start: int) -> ta.Iterator[Match]:
340
+ cp = ctx._grammar._rules_by_name_f[self._name_f].parser # noqa
341
+ for cm in ctx.iter_parse(cp, start):
342
+ yield Match(self, cm.start, cm.end, (cm,))
343
+
344
+
345
+ rule = RuleRef
@@ -0,0 +1,68 @@
1
+ import itertools
2
+ import textwrap
3
+ import typing as ta
4
+
5
+ from omlish import check
6
+
7
+ from .base import Grammar
8
+ from .base import Match
9
+ from .parsers import RuleRef
10
+
11
+
12
+ ##
13
+
14
+
15
+ def strip_insignificant_match_rules(m: Match, g: Grammar) -> Match:
16
+ def rec(c: Match) -> Match:
17
+ return c.flat_map_children(
18
+ lambda x: (
19
+ (rec(x),) if not (
20
+ isinstance((xp := x.parser), RuleRef) and
21
+ check.not_none(g.rule(xp.name)).insignificant
22
+ ) else ()
23
+ ),
24
+ )
25
+ return rec(m)
26
+
27
+
28
+ def only_match_rules(m: Match) -> Match:
29
+ def rec(c: Match) -> ta.Iterable[Match]:
30
+ if isinstance(c.parser, RuleRef):
31
+ return (c.flat_map_children(rec),)
32
+ else:
33
+ return itertools.chain.from_iterable(map(rec, c.children))
34
+ return m.flat_map_children(rec)
35
+
36
+
37
+ #
38
+
39
+
40
+ def parse_rules(
41
+ grammar: Grammar,
42
+ source: str,
43
+ root: str | None = None,
44
+ **kwargs: ta.Any,
45
+ ) -> Match | None:
46
+ if (match := grammar.parse(
47
+ source,
48
+ root,
49
+ **kwargs,
50
+ )) is None:
51
+ return None
52
+
53
+ match = only_match_rules(match)
54
+ match = strip_insignificant_match_rules(match, grammar)
55
+
56
+ return match
57
+
58
+
59
+ ##
60
+
61
+
62
+ def fix_grammar_ws(s: str) -> str:
63
+ return (
64
+ textwrap.dedent(s)
65
+ .rstrip()
66
+ .replace('\r', '')
67
+ .replace('\n', '\r\n')
68
+ ) + '\r\n'
@@ -0,0 +1,55 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import collections as col
5
+ from omlish import dispatch
6
+ from omlish import lang
7
+
8
+ from .base import Match
9
+ from .base import Parser
10
+ from .parsers import RuleRef
11
+
12
+
13
+ T = ta.TypeVar('T')
14
+
15
+
16
+ ##
17
+
18
+
19
+ class ParserVisitor(lang.Abstract, ta.Generic[T]):
20
+ @dispatch.method()
21
+ def visit_parser(self, p: Parser, m: Match) -> T:
22
+ raise TypeError(p)
23
+
24
+ #
25
+
26
+ def visit_match(self, m: Match) -> T:
27
+ return self.visit_parser(m.parser, m)
28
+
29
+
30
+ ##
31
+
32
+
33
+ class RuleVisitor(lang.Abstract, ta.Generic[T]):
34
+ _registry = col.AttrRegistry[ta.Callable, str]()
35
+
36
+ @classmethod
37
+ def register(cls, name):
38
+ return cls._registry.register(name)
39
+
40
+ @lang.cached_function
41
+ @classmethod
42
+ def _registry_cache(cls) -> col.AttrRegistryCache[ta.Callable, str, ta.Mapping[str, str]]:
43
+ def prepare(_, dct):
44
+ return col.make_map(((n, a) for a, (_, n) in dct.items()), strict=True)
45
+
46
+ return col.AttrRegistryCache(cls._registry, prepare)
47
+
48
+ def visit_rule(self, name: str, m: Match) -> T:
49
+ att = self._registry_cache().get(self.__class__)[name]
50
+ return getattr(self, att)(m)
51
+
52
+ #
53
+
54
+ def visit_match(self, m: Match) -> T:
55
+ return self.visit_rule(check.isinstance(m.parser, RuleRef).name, m)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omextra
3
- Version: 0.0.0.dev472
3
+ Version: 0.0.0.dev473
4
4
  Summary: omextra
5
5
  Author: wrmsr
6
6
  License-Expression: BSD-3-Clause
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Requires-Python: >=3.13
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: omlish==0.0.0.dev472
17
+ Requires-Dist: omlish==0.0.0.dev473
18
18
  Dynamic: license-file
19
19
 
20
20
  # Overview
@@ -1,5 +1,5 @@
1
1
  omextra/.omlish-manifests.json,sha256=E1M9UJ31RfpLfsZ2MfbN0_GAh_Lu_vj9wVJKPgak8jQ,290
2
- omextra/__about__.py,sha256=UmONS0zKtygpY7Z9AD42Kn1cajMEdLKHzUwG00kaaFM,689
2
+ omextra/__about__.py,sha256=8R-v5C4UWEiLEyDv1CoxATr7YTxZxs6-7QRlva-gGWY,706
3
3
  omextra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omextra/defs.py,sha256=iMaDGj5VSG7QdYA1s7MvIYTbtTsXc1msINsuuZym1vs,4902
5
5
  omextra/dynamic.py,sha256=i3aJRWwHJOmsrXI9a2iWCLa7pUQXx5YbMvUOS5LZ_Bs,6531
@@ -14,7 +14,18 @@ omextra/asyncs/bluelet/events.py,sha256=PJ55CuXNmvzhYYhMmIDOUWegWTMcn9IkxL4dHcjd
14
14
  omextra/asyncs/bluelet/files.py,sha256=wpvzFPfQltqPcSKUgmAUZ1sjSSawX_nr5rZ4InLhsTM,2424
15
15
  omextra/asyncs/bluelet/runner.py,sha256=pE080AUs66AIxY5WBOWqh-9V1i1JYOvxaE2wB8t72Mw,15516
16
16
  omextra/asyncs/bluelet/sockets.py,sha256=nTVPdLbsmmjI0e6G9Di2DA-JoTTnvu8xc_Yv8N_7g48,6781
17
+ omextra/collections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ omextra/collections/hamt/LICENSE,sha256=82rcXdtBwd6vGLddjx9Jk09kkwPL6yqqv1NzGjPUCoM,2460
19
+ omextra/collections/hamt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
+ omextra/collections/hamt/_hamt.c,sha256=LDYWBuAl4685DbAZICrzO--EfIN8PjHZq0MUJYBAD74,100898
17
21
  omextra/formats/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
+ omextra/formats/goyaml/LICENSE,sha256=qkavv9cjd59BFIFOMVMJMrC3FCEIELrBTA-GPhAFkoY,1071
23
+ omextra/formats/goyaml/__init__.py,sha256=HuJqVB6wyqzQcHMRCW9r3ciPnjl3UvhDT-LjRp7kHDo,1817
24
+ omextra/formats/goyaml/ast.py,sha256=55CyoNRiaDmu6YeKE_PRt51fE7zr35YcTWSDzVRjPRo,69984
25
+ omextra/formats/goyaml/errors.py,sha256=UQfuManw4kOJKnXrV6MjFqt0ZU6KkwZL75KMdQQ6ZyU,949
26
+ omextra/formats/goyaml/parsing.py,sha256=vZotOxOhLTrE9AGfXbSZcDrVC652PJ3K3ageu6aRT6Q,90558
27
+ omextra/formats/goyaml/scanning.py,sha256=X5hl5lhQAPtiqiKC0pGAo46D2rrB2nZOtJuQOAtaXDM,63208
28
+ omextra/formats/goyaml/tokens.py,sha256=fRshyMRU3XzZ5Pi9_C1F2BTzjtcrqIuIsHmQuqMu3Oo,29278
18
29
  omextra/formats/json/Json.g4,sha256=fYImsljcVPdlMTHBabM_rza2j4udqjfLQNxIz4S_TpY,1206
19
30
  omextra/formats/json/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
31
  omextra/formats/json/_antlr/JsonLexer.py,sha256=SYlMV8XKi_kJ9meEulNmm2B98hjdzz_xLyPsoqCyYoE,4957
@@ -52,6 +63,15 @@ omextra/sql/parsing/_antlr/MinisqlParser.py,sha256=htIMgNde8PqLj7mDV2cLo7kDiwn-a
52
63
  omextra/sql/parsing/_antlr/MinisqlVisitor.py,sha256=UPs2qA2VlNRP_LMwF0DpMxMir9tIS9w59vGTq07mmlI,10052
53
64
  omextra/sql/parsing/_antlr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
65
  omextra/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
+ omextra/text/abnf/LICENSE,sha256=UJzrhSePw9TVm0VfkVmx9NRHkPS1n6jx2UgajTb14ts,1054
67
+ omextra/text/abnf/__init__.py,sha256=v1ABrlcdhCB8ezqHZPl3MZ6SYoEZNerGET5MHjFYhP8,967
68
+ omextra/text/abnf/base.py,sha256=oO9e8Rd0kjdjJ6wWtpzIJOcY_E0QgUSAltpuwqWx-aQ,7476
69
+ omextra/text/abnf/core.py,sha256=VUD52hKgDsesvPjmhL1UZVXtpYr-EpWyBprdy722YTY,2303
70
+ omextra/text/abnf/errors.py,sha256=z_RMXMYhPwSUb1neJpJG-XUvkSS87uLJEX9p4wmXQfU,88
71
+ omextra/text/abnf/meta.py,sha256=ltiq70jpTB8Ab3jTfqRubmRdI-42SLPXztLk1_EWFLU,13704
72
+ omextra/text/abnf/parsers.py,sha256=BA5XdbiWh4UyabV4-rajSjHBOBXNa6ieTDs9CwM4nRU,9351
73
+ omextra/text/abnf/utils.py,sha256=OWJe9DvSidOLNzkbdUXdLupDKEIDy6TtQFPVjDmyCng,1420
74
+ omextra/text/abnf/visitors.py,sha256=kAWPmc3fAOLynLoVl_-ciG_TA3XG7HPca9_I1vI4rL0,1288
55
75
  omextra/text/antlr/__init__.py,sha256=88bMl_28cfSKslgOkMGYXqALgsHz3KC4LFvAVtzj7k8,89
56
76
  omextra/text/antlr/delimit.py,sha256=s0Jlu6oOamtuyWv_V98P0YC7HmgFJBF7GHVsDfMYTdI,3476
57
77
  omextra/text/antlr/dot.py,sha256=37ZBYpum-n6Xg9UGj1Wc0wyuR3gL_uX63KwrSzyWNmk,967
@@ -125,9 +145,9 @@ omextra/text/antlr/cli/__main__.py,sha256=ckYkj0drxabBVwWYewH2SS36TTeAxllZtS4xEl
125
145
  omextra/text/antlr/cli/cli.py,sha256=LW8pJNmySBOV3g8QxquPjUgxFv7YblzEyi555hHH3_M,1234
126
146
  omextra/text/antlr/cli/consts.py,sha256=HUYJP9j4RfeuuQv6HFd2oFMS0piWJ9Sq1tbeAs4OlBc,290
127
147
  omextra/text/antlr/cli/gen.py,sha256=HYleVptrpynwcl6GspX6O9_oMRSxwdYAQGuUFfDYse8,5236
128
- omextra-0.0.0.dev472.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
129
- omextra-0.0.0.dev472.dist-info/METADATA,sha256=f7prA1cDtyumqmLEewCCt5UWrQikbjbnRYhhtsMxVnQ,1001
130
- omextra-0.0.0.dev472.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
131
- omextra-0.0.0.dev472.dist-info/entry_points.txt,sha256=-MFAMks5HgZ60Ore0Wl5lKVKk8z4kf1Ls3WY9E_OlCU,37
132
- omextra-0.0.0.dev472.dist-info/top_level.txt,sha256=o1nCNRejLMcayDngLuWMWwaeOucz33BXbpuoVvvzjPc,8
133
- omextra-0.0.0.dev472.dist-info/RECORD,,
148
+ omextra-0.0.0.dev473.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
149
+ omextra-0.0.0.dev473.dist-info/METADATA,sha256=4KrfUl4grgwui8gUkPsKwH83Mo313ZP45Rjibw5Vqhk,1001
150
+ omextra-0.0.0.dev473.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
151
+ omextra-0.0.0.dev473.dist-info/entry_points.txt,sha256=-MFAMks5HgZ60Ore0Wl5lKVKk8z4kf1Ls3WY9E_OlCU,37
152
+ omextra-0.0.0.dev473.dist-info/top_level.txt,sha256=o1nCNRejLMcayDngLuWMWwaeOucz33BXbpuoVvvzjPc,8
153
+ omextra-0.0.0.dev473.dist-info/RECORD,,