omdev 0.0.0.dev210__py3-none-any.whl → 0.0.0.dev212__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.
omdev/scripts/interp.py CHANGED
@@ -1189,7 +1189,7 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
1189
1189
  ##
1190
1190
 
1191
1191
 
1192
- def camel_case(name: str, lower: bool = False) -> str:
1192
+ def camel_case(name: str, *, lower: bool = False) -> str:
1193
1193
  if not name:
1194
1194
  return ''
1195
1195
  s = ''.join(map(str.capitalize, name.split('_'))) # noqa
@@ -1206,6 +1206,27 @@ def snake_case(name: str) -> str:
1206
1206
  ##
1207
1207
 
1208
1208
 
1209
+ def is_dunder(name: str) -> bool:
1210
+ return (
1211
+ name[:2] == name[-2:] == '__' and
1212
+ name[2:3] != '_' and
1213
+ name[-3:-2] != '_' and
1214
+ len(name) > 4
1215
+ )
1216
+
1217
+
1218
+ def is_sunder(name: str) -> bool:
1219
+ return (
1220
+ name[0] == name[-1] == '_' and
1221
+ name[1:2] != '_' and
1222
+ name[-2:-1] != '_' and
1223
+ len(name) > 2
1224
+ )
1225
+
1226
+
1227
+ ##
1228
+
1229
+
1209
1230
  def strip_with_newline(s: str) -> str:
1210
1231
  if not s:
1211
1232
  return ''
@@ -1237,27 +1258,6 @@ def split_keep_delimiter(s, d):
1237
1258
  ##
1238
1259
 
1239
1260
 
1240
- def is_dunder(name: str) -> bool:
1241
- return (
1242
- name[:2] == name[-2:] == '__' and
1243
- name[2:3] != '_' and
1244
- name[-3:-2] != '_' and
1245
- len(name) > 4
1246
- )
1247
-
1248
-
1249
- def is_sunder(name: str) -> bool:
1250
- return (
1251
- name[0] == name[-1] == '_' and
1252
- name[1:2] != '_' and
1253
- name[-2:-1] != '_' and
1254
- len(name) > 2
1255
- )
1256
-
1257
-
1258
- ##
1259
-
1260
-
1261
1261
  def attr_repr(obj: ta.Any, *attrs: str) -> str:
1262
1262
  return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
1263
1263
 
@@ -2497,7 +2497,7 @@ def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
2497
2497
  ##
2498
2498
 
2499
2499
 
2500
- def camel_case(name: str, lower: bool = False) -> str:
2500
+ def camel_case(name: str, *, lower: bool = False) -> str:
2501
2501
  if not name:
2502
2502
  return ''
2503
2503
  s = ''.join(map(str.capitalize, name.split('_'))) # noqa
@@ -2514,6 +2514,27 @@ def snake_case(name: str) -> str:
2514
2514
  ##
2515
2515
 
2516
2516
 
2517
+ def is_dunder(name: str) -> bool:
2518
+ return (
2519
+ name[:2] == name[-2:] == '__' and
2520
+ name[2:3] != '_' and
2521
+ name[-3:-2] != '_' and
2522
+ len(name) > 4
2523
+ )
2524
+
2525
+
2526
+ def is_sunder(name: str) -> bool:
2527
+ return (
2528
+ name[0] == name[-1] == '_' and
2529
+ name[1:2] != '_' and
2530
+ name[-2:-1] != '_' and
2531
+ len(name) > 2
2532
+ )
2533
+
2534
+
2535
+ ##
2536
+
2537
+
2517
2538
  def strip_with_newline(s: str) -> str:
2518
2539
  if not s:
2519
2540
  return ''
@@ -2545,27 +2566,6 @@ def split_keep_delimiter(s, d):
2545
2566
  ##
2546
2567
 
2547
2568
 
2548
- def is_dunder(name: str) -> bool:
2549
- return (
2550
- name[:2] == name[-2:] == '__' and
2551
- name[2:3] != '_' and
2552
- name[-3:-2] != '_' and
2553
- len(name) > 4
2554
- )
2555
-
2556
-
2557
- def is_sunder(name: str) -> bool:
2558
- return (
2559
- name[0] == name[-1] == '_' and
2560
- name[1:2] != '_' and
2561
- name[-2:-1] != '_' and
2562
- len(name) > 2
2563
- )
2564
-
2565
-
2566
- ##
2567
-
2568
-
2569
2569
  def attr_repr(obj: ta.Any, *attrs: str) -> str:
2570
2570
  return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
2571
2571
 
File without changes
omdev/tokens/all.py ADDED
@@ -0,0 +1,35 @@
1
+ from .tokenizert import ( # noqa
2
+ TokenNames,
3
+ Token,
4
+ TokenOffset,
5
+
6
+ Tokenization,
7
+ )
8
+
9
+ from .utils import ( # noqa
10
+ Tokens,
11
+
12
+ WS_NAMES,
13
+ is_ws,
14
+ ignore_ws,
15
+
16
+ split_lines,
17
+ join_toks,
18
+ join_lines,
19
+
20
+ match_toks,
21
+ )
22
+
23
+
24
+ ##
25
+
26
+
27
+ ESCAPED_NL = TokenNames.ESCAPED_NL # noqa
28
+ UNIMPORTANT_WS = TokenNames.UNIMPORTANT_WS # noqa
29
+ NON_CODING_TOKENS = TokenNames.NON_CODING_TOKENS # noqa
30
+
31
+ curly_escape = Tokenization.curly_escape # noqa
32
+ src_to_tokens = Tokenization.src_to_tokens # noqa
33
+ parse_string_literal = Tokenization.parse_string_literal # noqa
34
+ tokens_to_src = Tokenization.tokens_to_src # noqa
35
+ rfind_string_parts = Tokenization.rfind_string_parts # noqa
@@ -0,0 +1,217 @@
1
+ # @omlish-lite
2
+ # ruff: noqa: UP006 UP007
3
+ # Copyright (c) 2017 Anthony Sottile
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11
+ # Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
15
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17
+ # https://github.com/asottile/tokenize-rt/blob/413692b7c1ad8a873caec39dd4f427d55ee538ea/tokenize_rt.py
18
+ import argparse
19
+ import io
20
+ import keyword
21
+ import re
22
+ import tokenize
23
+ import typing as ta
24
+
25
+ from omlish.lite.check import check
26
+
27
+
28
+ ##
29
+
30
+
31
+ class TokenNames:
32
+ def __new__(cls, *args, **kwargs): # noqa
33
+ raise TypeError
34
+
35
+ ESCAPED_NL = 'ESCAPED_NL'
36
+ UNIMPORTANT_WS = 'UNIMPORTANT_WS'
37
+ NON_CODING_TOKENS = frozenset(('COMMENT', ESCAPED_NL, 'NL', UNIMPORTANT_WS))
38
+
39
+
40
+ class TokenOffset(ta.NamedTuple):
41
+ line: ta.Optional[int] = None
42
+ utf8_byte_offset: ta.Optional[int] = None
43
+
44
+
45
+ class Token(ta.NamedTuple):
46
+ name: str
47
+ src: str
48
+ line: ta.Optional[int] = None
49
+ utf8_byte_offset: ta.Optional[int] = None
50
+
51
+ @property
52
+ def offset(self) -> TokenOffset:
53
+ return TokenOffset(self.line, self.utf8_byte_offset)
54
+
55
+ def matches(self, *, name: str, src: str) -> bool:
56
+ return self.name == name and self.src == src
57
+
58
+
59
+ ##
60
+
61
+
62
+ class Tokenization:
63
+ _STRING_RE = re.compile('^([^\'"]*)(.*)$', re.DOTALL)
64
+ _ESCAPED_NL_RE = re.compile(r'\\(\n|\r\n|\r)')
65
+
66
+ _NAMED_UNICODE_RE = re.compile(r'(?<!\\)(?:\\\\)*(\\N\{[^}]+\})')
67
+
68
+ @classmethod
69
+ def curly_escape(cls, s: str) -> str:
70
+ parts = cls._NAMED_UNICODE_RE.split(s)
71
+ return ''.join(
72
+ part.replace('{', '{{').replace('}', '}}') if i % 2 == 0 else part
73
+ for i, part in enumerate(parts)
74
+ )
75
+
76
+ @classmethod
77
+ def _re_partition(cls, regex: ta.Pattern[str], s: str) -> ta.Tuple[str, str, str]:
78
+ match = regex.search(s)
79
+ if match:
80
+ return s[:match.start()], s[slice(*match.span())], s[match.end():]
81
+ else:
82
+ return (s, '', '')
83
+
84
+ @classmethod
85
+ def src_to_tokens(cls, src: str) -> ta.List[Token]:
86
+ tokenize_target = io.StringIO(src)
87
+ lines = ('', *tokenize_target)
88
+
89
+ tokenize_target.seek(0)
90
+
91
+ tokens = []
92
+ last_line = 1
93
+ last_col = 0
94
+ end_offset = 0
95
+
96
+ gen = tokenize.generate_tokens(tokenize_target.readline)
97
+ for tok_type, tok_text, (sline, scol), (eline, ecol), line in gen:
98
+ if sline > last_line:
99
+ newtok = lines[last_line][last_col:]
100
+ for lineno in range(last_line + 1, sline):
101
+ newtok += lines[lineno]
102
+ if scol > 0:
103
+ newtok += lines[sline][:scol]
104
+
105
+ # a multiline unimportant whitespace may contain escaped newlines
106
+ while cls._ESCAPED_NL_RE.search(newtok):
107
+ ws, nl, newtok = cls._re_partition(cls._ESCAPED_NL_RE, newtok)
108
+ if ws:
109
+ tokens.append(
110
+ Token(TokenNames.UNIMPORTANT_WS, ws, last_line, end_offset),
111
+ )
112
+ end_offset += len(ws.encode())
113
+ tokens.append(Token(TokenNames.ESCAPED_NL, nl, last_line, end_offset))
114
+ end_offset = 0
115
+ last_line += 1
116
+ if newtok:
117
+ tokens.append(Token(TokenNames.UNIMPORTANT_WS, newtok, sline, 0))
118
+ end_offset = len(newtok.encode())
119
+ else:
120
+ end_offset = 0
121
+
122
+ elif scol > last_col:
123
+ newtok = line[last_col:scol]
124
+ tokens.append(Token(TokenNames.UNIMPORTANT_WS, newtok, sline, end_offset))
125
+ end_offset += len(newtok.encode())
126
+
127
+ tok_name = tokenize.tok_name[tok_type]
128
+
129
+ if tok_name == 'FSTRING_MIDDLE': # pragma: >=3.12 cover
130
+ if '{' in tok_text or '}' in tok_text:
131
+ new_tok_text = cls.curly_escape(tok_text)
132
+ ecol += len(new_tok_text) - len(tok_text)
133
+ tok_text = new_tok_text
134
+
135
+ tokens.append(Token(tok_name, tok_text, sline, end_offset))
136
+ last_line, last_col = eline, ecol
137
+ if sline != eline:
138
+ end_offset = len(lines[last_line][:last_col].encode())
139
+ else:
140
+ end_offset += len(tok_text.encode())
141
+
142
+ return tokens
143
+
144
+ @classmethod
145
+ def parse_string_literal(cls, src: str) -> ta.Tuple[str, str]:
146
+ """parse a string literal's source into (prefix, string)"""
147
+ match = check.not_none(cls._STRING_RE.match(src))
148
+ return match.group(1), match.group(2)
149
+
150
+ @classmethod
151
+ def tokens_to_src(cls, tokens: ta.Iterable[Token]) -> str:
152
+ return ''.join(tok.src for tok in tokens)
153
+
154
+ @classmethod
155
+ def rfind_string_parts(cls, tokens: ta.Sequence[Token], start: int) -> ta.Tuple[int, ...]:
156
+ """
157
+ Find the indicies of the string parts of a (joined) string literal.
158
+
159
+ - `i` should start at the end of the string literal
160
+ - returns `()` (an empty tuple) for things which are not string literals
161
+ """
162
+
163
+ ret = []
164
+ depth = 0
165
+ for i in range(start, -1, -1):
166
+ token = tokens[i]
167
+ if token.name == 'STRING':
168
+ ret.append(i)
169
+ elif token.name in TokenNames.NON_CODING_TOKENS:
170
+ pass
171
+ elif token.src == ')':
172
+ depth += 1
173
+ elif depth and token.src == '(':
174
+ depth -= 1
175
+ # if we closed the paren(s) make sure it was a parenthesized string
176
+ # and not actually a call
177
+ if depth == 0:
178
+ for j in range(i - 1, -1, -1):
179
+ tok = tokens[j]
180
+ if tok.name in TokenNames.NON_CODING_TOKENS:
181
+ pass
182
+ # this was actually a call and not a parenthesized string
183
+ elif (
184
+ tok.src in {']', ')'} or (
185
+ tok.name == 'NAME' and
186
+ tok.src not in keyword.kwlist
187
+ )
188
+ ):
189
+ return ()
190
+ else:
191
+ break
192
+ break
193
+ elif depth: # it looked like a string but wasn't
194
+ return ()
195
+ else:
196
+ break
197
+ return tuple(reversed(ret))
198
+
199
+
200
+ ##
201
+
202
+
203
+ if __name__ == '__main__':
204
+ def main(argv: ta.Optional[ta.Sequence[str]] = None) -> int:
205
+ parser = argparse.ArgumentParser()
206
+ parser.add_argument('filename')
207
+ args = parser.parse_args(argv)
208
+ with open(args.filename) as f:
209
+ tokens = Tokenization.src_to_tokens(f.read())
210
+
211
+ for token in tokens:
212
+ line, col = str(token.line), str(token.utf8_byte_offset)
213
+ print(f'{line}:{col} {token.name} {token.src!r}')
214
+
215
+ return 0
216
+
217
+ raise SystemExit(main())
@@ -1,16 +1,10 @@
1
1
  import itertools
2
2
  import typing as ta
3
3
 
4
- from omlish import lang
4
+ from .tokenizert import Token
5
5
 
6
6
 
7
- if ta.TYPE_CHECKING:
8
- import tokenize_rt as trt
9
- else:
10
- trt = lang.proxy_import('tokenize_rt')
11
-
12
-
13
- Tokens: ta.TypeAlias = ta.Sequence['trt.Token']
7
+ Tokens: ta.TypeAlias = ta.Sequence[Token]
14
8
 
15
9
 
16
10
  ##
@@ -25,15 +19,15 @@ WS_NAMES = (
25
19
  )
26
20
 
27
21
 
28
- def is_ws(tok: 'trt.Token') -> bool:
22
+ def is_ws(tok: Token) -> bool:
29
23
  return tok.name in WS_NAMES
30
24
 
31
25
 
32
26
  def ignore_ws(
33
- toks: ta.Iterable['trt.Token'],
27
+ toks: ta.Iterable[Token],
34
28
  *,
35
29
  keep: ta.Container[str] = (),
36
- ) -> ta.Iterable['trt.Token']:
30
+ ) -> ta.Iterable[Token]:
37
31
  return (
38
32
  t
39
33
  for t in toks
@@ -60,7 +54,7 @@ def join_lines(ls: ta.Iterable[Tokens]) -> str:
60
54
 
61
55
 
62
56
  def match_toks(
63
- ts: ta.Iterable['trt.Token'],
57
+ ts: ta.Iterable[Token],
64
58
  pat: ta.Sequence[tuple[str | None, str | tuple[str, ...] | None]],
65
59
  ) -> bool:
66
60
  it = iter(ts)
omdev/tools/mkenv.py ADDED
@@ -0,0 +1,131 @@
1
+ """
2
+ TODO:
3
+ - detect file extension
4
+
5
+ ==
6
+
7
+ export $(./python mkenv.py secrets.yml foo_access_token | xargs)
8
+ eval $(om mkenv -e secrets.yml foo_access_token)
9
+ """
10
+ import argparse
11
+ import json
12
+ import shlex
13
+ import sys
14
+ import typing as ta
15
+
16
+ from omlish import check
17
+ from omlish.configs.formats import DEFAULT_CONFIG_FILE_LOADER
18
+ from omlish.specs import jmespath
19
+
20
+
21
+ ##
22
+
23
+
24
+ VALUE_TYPES: tuple[type, ...] = (
25
+ str,
26
+ int,
27
+ float,
28
+ bool,
29
+ )
30
+
31
+
32
+ def extract_item(
33
+ obj: ta.Any,
34
+ item: str,
35
+ *,
36
+ uppercase_keys: bool = False,
37
+ ) -> tuple[str, str]:
38
+ if '=' not in item:
39
+ k = item
40
+ v = obj[k]
41
+ if uppercase_keys:
42
+ k = k.upper()
43
+
44
+ else:
45
+ k, p = item.split('=')
46
+ v = jmespath.search(p, obj)
47
+
48
+ #
49
+
50
+ if isinstance(v, str):
51
+ s = v
52
+
53
+ elif isinstance(v, bool):
54
+ s = 'true' if v else 'false'
55
+
56
+ else:
57
+ check.isinstance(v, VALUE_TYPES)
58
+ s = str(v)
59
+
60
+ #
61
+
62
+ check.equal(s.strip(), s)
63
+ for c in '\t\n':
64
+ check.not_in(c, s)
65
+
66
+ #
67
+
68
+ return (k, s)
69
+
70
+
71
+ def extract_items(
72
+ obj: ta.Any,
73
+ items: ta.Iterable[str],
74
+ **kwargs: ta.Any,
75
+ ) -> dict[str, str]:
76
+ return dict(
77
+ extract_item(obj, item, **kwargs)
78
+ for item in items
79
+ )
80
+
81
+
82
+ def _main() -> None:
83
+ parser = argparse.ArgumentParser()
84
+
85
+ parser.add_argument('file')
86
+ parser.add_argument('-e', '--for-eval', action='store_true')
87
+ parser.add_argument('-u', '--uppercase', action='store_true')
88
+ parser.add_argument('item', nargs='*')
89
+
90
+ args = parser.parse_args()
91
+
92
+ #
93
+
94
+ if args.file == '-':
95
+ obj = json.loads(sys.stdin.read())
96
+
97
+ else:
98
+ data = DEFAULT_CONFIG_FILE_LOADER.load_file(args.file)
99
+ obj = data.as_map()
100
+
101
+ #
102
+
103
+ items = extract_items(
104
+ obj,
105
+ args.item,
106
+ uppercase_keys=args.uppercase,
107
+ )
108
+
109
+ #
110
+
111
+ if args.for_eval:
112
+ cmd = ' '.join([
113
+ 'export',
114
+ *[f'{k}={qv if (qv := shlex.quote(v)) != v else v}' for k, v in items.items()],
115
+ ])
116
+ print(cmd)
117
+
118
+ else:
119
+ for k, v in items.items():
120
+ print(f'{k}={v}')
121
+
122
+
123
+ # @omlish-manifest
124
+ _CLI_MODULE = {'$omdev.cli.types.CliModule': {
125
+ 'cmd_name': ['mkenv'],
126
+ 'mod_name': __name__,
127
+ }}
128
+
129
+
130
+ if __name__ == '__main__':
131
+ _main()
omdev/tools/mkrelimp.py CHANGED
@@ -4,12 +4,10 @@ import logging
4
4
  import os.path
5
5
  import typing as ta
6
6
 
7
- import tokenize_rt as trt
8
-
9
7
  from omlish.logs import all as logs
10
8
 
11
- from .. import tokens as tks
12
9
  from ..cli import CliModule
10
+ from ..tokens import all as tks
13
11
 
14
12
 
15
13
  T = ta.TypeVar('T')
@@ -91,8 +89,8 @@ class Processor:
91
89
  ##
92
90
 
93
91
  new_tks = list(interleave(
94
- trt.Token(name='OP', src='.'),
95
- [trt.Token(name='NAME', src=p) for p in rel_imp_name_parts],
92
+ tks.Token(name='OP', src='.'),
93
+ [tks.Token(name='NAME', src=p) for p in rel_imp_name_parts],
96
94
  ))
97
95
  out_tks = [
98
96
  *pfx,
@@ -111,7 +109,7 @@ class Processor:
111
109
  with open(src_file) as f:
112
110
  src = f.read()
113
111
 
114
- ts = trt.src_to_tokens(src)
112
+ ts = tks.src_to_tokens(src)
115
113
  in_ls = tks.split_lines(ts)
116
114
  out_ls = [
117
115
  self.process_line_tks(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omdev
3
- Version: 0.0.0.dev210
3
+ Version: 0.0.0.dev212
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish==0.0.0.dev210
15
+ Requires-Dist: omlish==0.0.0.dev212
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -24,7 +24,6 @@ Requires-Dist: mypy~=1.11; extra == "all"
24
24
  Requires-Dist: gprof2dot~=2024.6; extra == "all"
25
25
  Requires-Dist: prompt-toolkit~=3.0; extra == "all"
26
26
  Requires-Dist: segno~=1.6; extra == "all"
27
- Requires-Dist: tokenize-rt~=6.1; extra == "all"
28
27
  Requires-Dist: wheel~=0.44; extra == "all"
29
28
  Provides-Extra: black
30
29
  Requires-Dist: black~=24.10; extra == "black"
@@ -43,7 +42,5 @@ Provides-Extra: ptk
43
42
  Requires-Dist: prompt-toolkit~=3.0; extra == "ptk"
44
43
  Provides-Extra: qr
45
44
  Requires-Dist: segno~=1.6; extra == "qr"
46
- Provides-Extra: tokens
47
- Requires-Dist: tokenize-rt~=6.1; extra == "tokens"
48
45
  Provides-Extra: wheel
49
46
  Requires-Dist: wheel~=0.44; extra == "wheel"