omlish 0.0.0.dev212__py3-none-any.whl → 0.0.0.dev214__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 (39) hide show
  1. omlish/.manifests.json +4 -4
  2. omlish/__about__.py +3 -5
  3. omlish/antlr/__init__.py +3 -0
  4. omlish/antlr/parsing.py +34 -2
  5. omlish/asyncs/asyncio/asyncio.py +34 -0
  6. omlish/asyncs/ioproxy/__init__.py +1 -0
  7. omlish/asyncs/ioproxy/all.py +32 -0
  8. omlish/asyncs/ioproxy/io.py +242 -0
  9. omlish/asyncs/ioproxy/proxier.py +154 -0
  10. omlish/asyncs/ioproxy/proxy.py +141 -0
  11. omlish/asyncs/ioproxy/typing.py +108 -0
  12. omlish/check.py +1 -0
  13. omlish/configs/processing/matching.py +9 -1
  14. omlish/formats/json/stream/lex.py +1 -0
  15. omlish/formats/json5/Json5.g4 +172 -0
  16. omlish/formats/json5/__init__.py +8 -0
  17. omlish/formats/json5/_antlr/Json5Lexer.py +353 -0
  18. omlish/formats/json5/_antlr/Json5Listener.py +78 -0
  19. omlish/formats/json5/_antlr/Json5Parser.py +616 -0
  20. omlish/formats/json5/_antlr/Json5Visitor.py +51 -0
  21. omlish/formats/json5/_antlr/__init__.py +0 -0
  22. omlish/formats/{json5.py → json5/codec.py} +6 -11
  23. omlish/formats/json5/errors.py +2 -0
  24. omlish/formats/json5/literals.py +130 -0
  25. omlish/formats/json5/parsing.py +79 -0
  26. omlish/io/abc.py +1 -0
  27. omlish/lang/__init__.py +2 -0
  28. omlish/lang/imports.py +4 -0
  29. omlish/lang/strings.py +33 -1
  30. omlish/lite/check.py +23 -0
  31. omlish/lite/contextmanagers.py +39 -0
  32. omlish/os/files.py +17 -30
  33. omlish/os/temp.py +50 -0
  34. {omlish-0.0.0.dev212.dist-info → omlish-0.0.0.dev214.dist-info}/METADATA +5 -7
  35. {omlish-0.0.0.dev212.dist-info → omlish-0.0.0.dev214.dist-info}/RECORD +39 -22
  36. {omlish-0.0.0.dev212.dist-info → omlish-0.0.0.dev214.dist-info}/LICENSE +0 -0
  37. {omlish-0.0.0.dev212.dist-info → omlish-0.0.0.dev214.dist-info}/WHEEL +0 -0
  38. {omlish-0.0.0.dev212.dist-info → omlish-0.0.0.dev214.dist-info}/entry_points.txt +0 -0
  39. {omlish-0.0.0.dev212.dist-info → omlish-0.0.0.dev214.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,141 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import functools
4
+ import inspect
5
+ import typing as ta
6
+
7
+ from ...lite.check import check
8
+
9
+
10
+ AsyncIoProxyRunner = ta.Callable[[ta.Callable], ta.Awaitable] # ta.TypeAlias
11
+
12
+
13
+ ##
14
+
15
+
16
+ _ASYNC_IO_PROXY_WRAPPER_NAME_ATTRS = ('__name__', '__qualname__')
17
+ _ASYNC_IO_PROXY_WRAPPER_ASSIGNMENTS = tuple(
18
+ a
19
+ for a in functools.WRAPPER_ASSIGNMENTS
20
+ if a not in _ASYNC_IO_PROXY_WRAPPER_NAME_ATTRS
21
+ )
22
+
23
+
24
+ def async_io_proxy_fn(fn, runner, *, result_wrapper=None):
25
+ @functools.wraps(fn, assigned=_ASYNC_IO_PROXY_WRAPPER_ASSIGNMENTS)
26
+ async def run(*args, **kwargs):
27
+ ret = await runner(functools.partial(fn, *args, **kwargs))
28
+ if result_wrapper is not None:
29
+ ret = result_wrapper(ret)
30
+ return ret
31
+
32
+ for na in _ASYNC_IO_PROXY_WRAPPER_NAME_ATTRS:
33
+ setattr(run, na, f'{getattr(run, na)}:{getattr(fn, na)}')
34
+
35
+ return run
36
+
37
+
38
+ ##
39
+
40
+
41
+ @dc.dataclass(frozen=True)
42
+ class AsyncIoProxyTarget:
43
+ obj: ta.Any
44
+ runner: AsyncIoProxyRunner
45
+
46
+
47
+ class AsyncIoProxy:
48
+ def __init__(self, target: AsyncIoProxyTarget) -> None:
49
+ super().__init__()
50
+
51
+ self._target = check.isinstance(target, AsyncIoProxyTarget)
52
+
53
+ #
54
+
55
+ class _Descriptor:
56
+ def __init__(self, name) -> None:
57
+ super().__init__()
58
+
59
+ self._name = name
60
+
61
+ def __get__(self, instance, owner=None):
62
+ if instance is None:
63
+ return self
64
+
65
+ target: AsyncIoProxyTarget = instance._target # noqa
66
+ v = self._get(target, instance)
67
+
68
+ setattr(instance, self._name, v)
69
+ return v
70
+
71
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
72
+ raise NotImplementedError
73
+
74
+ class _Property(_Descriptor):
75
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
76
+ return getattr(target.obj, self._name)
77
+
78
+ class _Method(_Descriptor):
79
+ def __call__(self, instance, *args, **kwargs):
80
+ return self.__get__(instance)(*args, **kwargs)
81
+
82
+ class _SyncMethod(_Method):
83
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
84
+ return getattr(target.obj, self._name)
85
+
86
+ class _AsyncMethod(_Method):
87
+ SPECIAL_METHOD_NAMES: ta.ClassVar[ta.Mapping[str, str]] = {
88
+ '__aenter__': '__enter__',
89
+ '__aexit__': '__exit__',
90
+ }
91
+
92
+ def _get(self, target: AsyncIoProxyTarget, instance: ta.Any) -> ta.Any:
93
+ fa = self.SPECIAL_METHOD_NAMES.get(self._name, self._name)
94
+ fn = getattr(target.obj, fa)
95
+ if fa == '__enter__':
96
+ result_wrapper = lambda _: instance
97
+ else:
98
+ result_wrapper = None
99
+ run = async_io_proxy_fn(fn, target.runner, result_wrapper=result_wrapper)
100
+ return run
101
+
102
+ #
103
+
104
+ __proxied_cls__: ta.ClassVar[type]
105
+
106
+ def __init_subclass__(cls, *, proxied_cls=None, **kwargs): # noqa
107
+ super().__init_subclass__()
108
+
109
+ cls.__proxied_cls__ = check.isinstance(proxied_cls, (type, None))
110
+
111
+ for n, v in dict(cls.__dict__).items():
112
+ if n.startswith('_') and n not in cls._AsyncMethod.SPECIAL_METHOD_NAMES:
113
+ continue
114
+
115
+ if isinstance(v, property):
116
+ setattr(cls, n, cls._Property(n))
117
+
118
+ elif callable(v):
119
+ if inspect.iscoroutinefunction(v):
120
+ setattr(cls, n, cls._AsyncMethod(n))
121
+ else:
122
+ setattr(cls, n, cls._SyncMethod(n))
123
+
124
+ else:
125
+ raise TypeError(v)
126
+
127
+
128
+ ##
129
+
130
+
131
+ @functools.singledispatch
132
+ def async_io_proxy_cls_for(obj: ta.Any) -> ta.Optional[ta.Type[AsyncIoProxy]]:
133
+ return None
134
+
135
+
136
+ def _register_async_io_proxy_cls(cls):
137
+ async_io_proxy_cls_for.register(
138
+ check.isinstance(cls.__dict__['__proxied_cls__'], type),
139
+ lambda obj: cls,
140
+ )
141
+ return cls
@@ -0,0 +1,108 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import typing as ta
3
+
4
+ from .proxy import AsyncIoProxy
5
+ from .proxy import _register_async_io_proxy_cls
6
+
7
+
8
+ SelfT = ta.TypeVar('SelfT')
9
+
10
+ AnyStrT = ta.TypeVar('AnyStrT', bytes, str)
11
+
12
+
13
+ ##
14
+
15
+
16
+ @_register_async_io_proxy_cls
17
+ class TypingIO_AsyncIoProxy(AsyncIoProxy, ta.Generic[AnyStrT], proxied_cls=ta.IO): # noqa
18
+ @property
19
+ def mode(self) -> str:
20
+ raise TypeError
21
+
22
+ @property
23
+ def name(self) -> str:
24
+ raise TypeError
25
+
26
+ async def close(self) -> None:
27
+ raise TypeError
28
+
29
+ @property
30
+ def closed(self) -> bool:
31
+ raise TypeError
32
+
33
+ def fileno(self) -> int:
34
+ raise TypeError
35
+
36
+ async def flush(self) -> None:
37
+ raise TypeError
38
+
39
+ def isatty(self) -> bool:
40
+ raise TypeError
41
+
42
+ async def read(self, n: int = -1) -> AnyStrT:
43
+ raise TypeError
44
+
45
+ def readable(self) -> bool:
46
+ raise TypeError
47
+
48
+ async def readline(self, limit: int = -1) -> AnyStrT:
49
+ raise TypeError
50
+
51
+ async def readlines(self, hint: int = -1) -> ta.List[AnyStrT]:
52
+ raise TypeError
53
+
54
+ async def seek(self, offset: int, whence: int = 0) -> int:
55
+ raise TypeError
56
+
57
+ def seekable(self) -> bool:
58
+ raise TypeError
59
+
60
+ async def tell(self) -> int:
61
+ raise TypeError
62
+
63
+ async def truncate(self, size: ta.Optional[int] = None) -> int:
64
+ raise TypeError
65
+
66
+ def writable(self) -> bool:
67
+ raise TypeError
68
+
69
+ async def write(self, s: AnyStrT) -> int:
70
+ raise TypeError
71
+
72
+ async def writelines(self, lines: ta.List[AnyStrT]) -> None:
73
+ raise TypeError
74
+
75
+ async def __aenter__(self: SelfT) -> SelfT:
76
+ raise TypeError
77
+
78
+ async def __aexit__(self, exc_type, exc_value, exc_tb):
79
+ raise TypeError
80
+
81
+
82
+ @_register_async_io_proxy_cls
83
+ class TypingBinaryIO_AsyncIoProxy(TypingIO_AsyncIoProxy[bytes], proxied_cls=ta.BinaryIO): # noqa
84
+ def write(self, s: ta.Union[bytes, bytearray]) -> int: # type: ignore[override]
85
+ raise TypeError
86
+
87
+
88
+ @_register_async_io_proxy_cls
89
+ class TypingTextIO_AsyncIoProxy(TypingIO_AsyncIoProxy[str], proxied_cls=ta.TextIO): # noqa
90
+ # @property
91
+ # def buffer(self) -> BinaryIO:
92
+ # pass
93
+
94
+ @property
95
+ def encoding(self) -> str:
96
+ raise TypeError
97
+
98
+ @property
99
+ def errors(self) -> ta.Optional[str]:
100
+ raise TypeError
101
+
102
+ @property
103
+ def line_buffering(self) -> bool:
104
+ raise TypeError
105
+
106
+ @property
107
+ def newlines(self) -> ta.Any:
108
+ raise TypeError
omlish/check.py CHANGED
@@ -85,6 +85,7 @@ not_none = check.not_none
85
85
  #
86
86
 
87
87
  equal = check.equal
88
+ not_equal = check.not_equal
88
89
  is_ = check.is_
89
90
  is_not = check.is_not
90
91
  callable = check.callable # noqa
@@ -29,8 +29,16 @@ class MatchingConfigRewriter(ConfigRewriter):
29
29
  self._paths = frozenset(check.isinstance(p, tuple) for p in paths)
30
30
  self._recurse = recurse
31
31
 
32
+ def match_path(self, path: ConfigRewriterPath) -> bool:
33
+ for test in self._paths:
34
+ if len(test) != len(path):
35
+ continue
36
+ if all(t is None or p == t for p, t in zip(path, test)):
37
+ return True
38
+ return False
39
+
32
40
  def rewrite(self, ctx: ConfigRewriter.Context[T]) -> T:
33
- if ctx.path in self._paths:
41
+ if self.match_path(ctx.path):
34
42
  no = self._fn(ctx.obj)
35
43
  if not self._recurse:
36
44
  return no
@@ -4,6 +4,7 @@ TODO:
4
4
  - max recursion depth
5
5
  - mark start pos of tokens, currently returning end
6
6
  - _do_string inner loop optimization somehow
7
+ - json5 mode
7
8
  """
8
9
  import dataclasses as dc
9
10
  import io
@@ -0,0 +1,172 @@
1
+ // Student Main
2
+ // 2020-07-22
3
+ // Public domain
4
+
5
+ // JSON5 is a superset of JSON, it included some feature from ES5.1
6
+ // See https://json5.org/
7
+ // Derived from ../json/JSON.g4 which original derived from http://json.org
8
+
9
+ // $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false
10
+ // $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging
11
+
12
+ grammar Json5;
13
+
14
+ json5
15
+ : value? EOF
16
+ ;
17
+
18
+ obj
19
+ : '{' pair (',' pair)* ','? '}'
20
+ | '{' '}'
21
+ ;
22
+
23
+ pair
24
+ : key ':' value
25
+ ;
26
+
27
+ key
28
+ : STRING
29
+ | IDENTIFIER
30
+ | LITERAL
31
+ | NUMERIC_LITERAL
32
+ ;
33
+
34
+ value
35
+ : STRING
36
+ | number
37
+ | obj
38
+ | arr
39
+ | LITERAL
40
+ ;
41
+
42
+ arr
43
+ : '[' value (',' value)* ','? ']'
44
+ | '[' ']'
45
+ ;
46
+
47
+ number
48
+ : SYMBOL? (NUMERIC_LITERAL | NUMBER)
49
+ ;
50
+
51
+ // Lexer
52
+
53
+ SINGLE_LINE_COMMENT
54
+ : '//' .*? (NEWLINE | EOF) -> skip
55
+ ;
56
+
57
+ MULTI_LINE_COMMENT
58
+ : '/*' .*? '*/' -> skip
59
+ ;
60
+
61
+ LITERAL
62
+ : 'true'
63
+ | 'false'
64
+ | 'null'
65
+ ;
66
+
67
+ STRING
68
+ : '"' DOUBLE_QUOTE_CHAR* '"'
69
+ | '\'' SINGLE_QUOTE_CHAR* '\''
70
+ ;
71
+
72
+ fragment DOUBLE_QUOTE_CHAR
73
+ : ~["\\\r\n]
74
+ | ESCAPE_SEQUENCE
75
+ ;
76
+
77
+ fragment SINGLE_QUOTE_CHAR
78
+ : ~['\\\r\n]
79
+ | ESCAPE_SEQUENCE
80
+ ;
81
+
82
+ fragment ESCAPE_SEQUENCE
83
+ : '\\' (
84
+ NEWLINE
85
+ | UNICODE_SEQUENCE // \u1234
86
+ | ['"\\/bfnrtv] // single escape char
87
+ | ~['"\\bfnrtv0-9xu\r\n] // non escape char
88
+ | '0' // \0
89
+ | 'x' HEX HEX // \x3a
90
+ )
91
+ ;
92
+
93
+ NUMBER
94
+ : INT ('.' [0-9]*)? EXP? // +1.e2, 1234, 1234.5
95
+ | '.' [0-9]+ EXP? // -.2e3
96
+ | '0' [xX] HEX+ // 0x12345678
97
+ ;
98
+
99
+ NUMERIC_LITERAL
100
+ : 'Infinity'
101
+ | 'NaN'
102
+ ;
103
+
104
+ SYMBOL
105
+ : '+'
106
+ | '-'
107
+ ;
108
+
109
+ fragment HEX
110
+ : [0-9a-fA-F]
111
+ ;
112
+
113
+ fragment INT
114
+ : '0'
115
+ | [1-9] [0-9]*
116
+ ;
117
+
118
+ fragment EXP
119
+ : [Ee] SYMBOL? [0-9]*
120
+ ;
121
+
122
+ IDENTIFIER
123
+ : IDENTIFIER_START IDENTIFIER_PART*
124
+ ;
125
+
126
+ fragment IDENTIFIER_START
127
+ : [\p{L}]
128
+ | '$'
129
+ | '_'
130
+ | '\\' UNICODE_SEQUENCE
131
+ ;
132
+
133
+ fragment IDENTIFIER_PART
134
+ : IDENTIFIER_START
135
+ | [\p{M}]
136
+ | [\p{N}]
137
+ | [\p{Pc}]
138
+ | '\u200C'
139
+ | '\u200D'
140
+ ;
141
+
142
+ fragment UNICODE_SEQUENCE
143
+ : 'u' HEX HEX HEX HEX
144
+ ;
145
+
146
+ fragment NEWLINE
147
+ : '\r\n'
148
+ | [\r\n\u2028\u2029]
149
+ ;
150
+
151
+ fragment WS1
152
+ : '\u0009'
153
+ | '\u000A'
154
+ | '\u000B'
155
+ | '\u000C'
156
+ | '\u000D'
157
+ | '\u0020'
158
+ | '\u00A0'
159
+ | '\u2028'
160
+ | '\u2029'
161
+ | '\uFEFF'
162
+
163
+ | '\u1680'
164
+ | '\u2000' ..'\u200A'
165
+ | '\u202F'
166
+ | '\u205F'
167
+ | '\u3000'
168
+ ;
169
+
170
+ WS
171
+ : WS1+ -> skip
172
+ ;
@@ -0,0 +1,8 @@
1
+ from .codec import ( # noqa
2
+ dumps,
3
+ loads,
4
+ )
5
+
6
+ from .errors import ( # noqa
7
+ Json5Error,
8
+ )