omdev 0.0.0.dev282__py3-none-any.whl → 0.0.0.dev283__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/.manifests.json CHANGED
@@ -11,11 +11,23 @@
11
11
  }
12
12
  }
13
13
  },
14
+ {
15
+ "module": ".attrdocs",
16
+ "attr": "_CLI_MODULE",
17
+ "file": "omdev/attrdocs.py",
18
+ "line": 146,
19
+ "value": {
20
+ "$.cli.types.CliModule": {
21
+ "cmd_name": "py/attrdocs",
22
+ "mod_name": "omdev.attrdocs"
23
+ }
24
+ }
25
+ },
14
26
  {
15
27
  "module": ".bracepy",
16
28
  "attr": "_CLI_MODULE",
17
29
  "file": "omdev/bracepy.py",
18
- "line": 88,
30
+ "line": 94,
19
31
  "value": {
20
32
  "$.cli.types.CliModule": {
21
33
  "cmd_name": "bracepy",
@@ -51,7 +63,7 @@
51
63
  "module": ".classdot",
52
64
  "attr": "_CLI_MODULE",
53
65
  "file": "omdev/classdot.py",
54
- "line": 62,
66
+ "line": 65,
55
67
  "value": {
56
68
  "$.cli.types.CliModule": {
57
69
  "cmd_name": "py/classdot",
@@ -75,7 +87,7 @@
75
87
  "module": ".findimports",
76
88
  "attr": "_CLI_MODULE",
77
89
  "file": "omdev/findimports.py",
78
- "line": 81,
90
+ "line": 87,
79
91
  "value": {
80
92
  "$.cli.types.CliModule": {
81
93
  "cmd_name": "py/findimports",
@@ -87,7 +99,7 @@
87
99
  "module": ".imgur",
88
100
  "attr": "_FOO_CLI_MODULE",
89
101
  "file": "omdev/imgur.py",
90
- "line": 130,
102
+ "line": 133,
91
103
  "value": {
92
104
  "$.cli.types.CliModule": {
93
105
  "cmd_name": "imgur",
omdev/attrdocs.py ADDED
@@ -0,0 +1,177 @@
1
+ # ruff: noqa: N802
2
+ import ast
3
+ import dataclasses as dc
4
+ import inspect
5
+ import typing as ta
6
+
7
+ from omlish import check
8
+ from omlish import lang
9
+
10
+ from .tokens import all as tks
11
+
12
+
13
+ ##
14
+
15
+
16
+ @dc.dataclass(frozen=True)
17
+ class AttrDoc:
18
+ docstring: str | None = None
19
+ trailing_comment: str | None = None
20
+ preceding_comment: str | None = None
21
+
22
+ __repr__ = lang.AttrRepr.of(
23
+ 'docstring',
24
+ 'trailing_comment',
25
+ 'preceding_comment',
26
+ value_filter=bool,
27
+ )
28
+
29
+
30
+ _EMPTY_ATTR_DOC = AttrDoc()
31
+
32
+
33
+ ##
34
+
35
+
36
+ class _AttrDocAstVisitor(ast.NodeVisitor):
37
+ def __init__(
38
+ self,
39
+ *,
40
+ tok_lines: ta.Sequence[tks.Tokens] | None = None,
41
+ ) -> None:
42
+ super().__init__()
43
+
44
+ self._tok_lines = tok_lines
45
+
46
+ self._attr_docs: dict[str, AttrDoc] = {}
47
+ self._target: str | None = None
48
+ self._prev_node_type: type[ast.AST] | None = None
49
+
50
+ @property
51
+ def attr_docs(self) -> ta.Mapping[str, AttrDoc]:
52
+ return self._attr_docs
53
+
54
+ #
55
+
56
+ def visit(self, node: ast.AST) -> ta.Any:
57
+ if isinstance(node, (ast.AsyncFunctionDef, ast.FunctionDef)):
58
+ self._prev_node_type = None
59
+ return None
60
+ node_result = super().visit(node)
61
+ self._prev_node_type = type(node)
62
+ return node_result
63
+
64
+ #
65
+
66
+ @staticmethod
67
+ def _comment_tok_src(tok: tks.Token) -> str:
68
+ check.state(tok.name == 'COMMENT')
69
+ tc = tok.src
70
+ check.state(tc[0] == '#')
71
+ return tc[1:].lstrip()
72
+
73
+ def _set_target(self, node: ast.Name) -> None:
74
+ self._target = node.id
75
+
76
+ ad = _EMPTY_ATTR_DOC
77
+
78
+ if self._tok_lines is not None:
79
+ line = self._tok_lines[node.lineno - 1]
80
+ for t in reversed(line):
81
+ if t.name not in tks.WS_NAMES:
82
+ break
83
+ if t.name == 'COMMENT':
84
+ ad = dc.replace(ad, trailing_comment=self._comment_tok_src(t))
85
+ break
86
+
87
+ pll: list[str] = []
88
+ pln = node.lineno - 1
89
+ while pln > 0:
90
+ line = self._tok_lines[pln - 1]
91
+ no_ws_line = list(tks.ignore_ws(line, keep={'COMMENT'}))
92
+ if not no_ws_line or no_ws_line[0].name != 'COMMENT': # noqa
93
+ break
94
+ pll.append(self._comment_tok_src(no_ws_line[0]))
95
+ pln -= 1
96
+ if pll:
97
+ ad = dc.replace(ad, preceding_comment='\n'.join(reversed(pll)))
98
+
99
+ if ad is not _EMPTY_ATTR_DOC:
100
+ self._attr_docs[node.id] = ad
101
+
102
+ def visit_AnnAssign(self, node: ast.AnnAssign) -> ta.Any:
103
+ if isinstance(target := node.target, ast.Name):
104
+ self._set_target(target)
105
+
106
+ def visit_Assign(self, node: ast.Assign) -> ta.Any:
107
+ if len(node.targets) == 1 and isinstance(target := node.targets[0], ast.Name):
108
+ self._set_target(target) # noqa
109
+
110
+ #
111
+
112
+ def visit_Expr(self, node: ast.Expr) -> ta.Any:
113
+ if (
114
+ isinstance(node.value, ast.Constant) and
115
+ isinstance(node.value.value, str) and
116
+ self._prev_node_type in (ast.Assign, ast.AnnAssign)
117
+ ):
118
+ docstring = inspect.cleandoc(node.value.value)
119
+ if self._target:
120
+ ex = self._attr_docs.get(self._target, _EMPTY_ATTR_DOC)
121
+ check.none(ex.docstring)
122
+ self._attr_docs[self._target] = dc.replace(ex, docstring=docstring)
123
+ self._target = None
124
+
125
+
126
+ def extract_attr_docs(src: str) -> ta.Mapping[str, AttrDoc]:
127
+ if not src:
128
+ return {}
129
+
130
+ toks = tks.src_to_tokens(src)
131
+ tok_lines = tks.split_lines_dense(toks)
132
+
133
+ src_ast = ast.parse(src)
134
+
135
+ # import astpretty
136
+ # astpretty.pprint(src_ast)
137
+
138
+ ast_visitor = _AttrDocAstVisitor(tok_lines=tok_lines)
139
+ ast_visitor.visit(src_ast)
140
+ return ast_visitor.attr_docs
141
+
142
+
143
+ ##
144
+
145
+
146
+ # @omlish-manifest
147
+ _CLI_MODULE = {'$omdev.cli.types.CliModule': {
148
+ 'cmd_name': 'py/attrdocs',
149
+ 'mod_name': __name__,
150
+ }}
151
+
152
+
153
+ if __name__ == '__main__':
154
+ def _main() -> None:
155
+ import argparse
156
+
157
+ parser = argparse.ArgumentParser()
158
+ parser.add_argument('file')
159
+ args = parser.parse_args()
160
+
161
+ #
162
+
163
+ with open(args.file) as f:
164
+ src = f.read()
165
+
166
+ attr_docs = extract_attr_docs(src)
167
+
168
+ #
169
+
170
+ import json
171
+
172
+ print(json.dumps({
173
+ a: {k: v for k, v in dc.asdict(ad).items() if v}
174
+ for a, ad in sorted(attr_docs.items(), key=lambda t: t[0])
175
+ }))
176
+
177
+ _main()
omdev/bracepy.py CHANGED
@@ -7,6 +7,9 @@ import io
7
7
  import tokenize
8
8
 
9
9
 
10
+ ##
11
+
12
+
10
13
  def translate_brace_python(
11
14
  s: str,
12
15
  *,
@@ -85,6 +88,9 @@ def translate_brace_python(
85
88
  return ret.getvalue()
86
89
 
87
90
 
91
+ ##
92
+
93
+
88
94
  # @omlish-manifest
89
95
  _CLI_MODULE = {'$omdev.cli.types.CliModule': {
90
96
  'cmd_name': 'bracepy',
omdev/classdot.py CHANGED
@@ -10,6 +10,9 @@ from omlish.graphs import dot
10
10
  from .cli import CliModule
11
11
 
12
12
 
13
+ ##
14
+
15
+
13
16
  def gen_class_dot(roots: ta.Iterable[type]) -> dot.Graph:
14
17
  roots = set(roots)
15
18
  root_tup = tuple(roots)
omdev/cmake.py CHANGED
@@ -4,6 +4,9 @@ import typing as ta
4
4
  from omlish import dataclasses as dc
5
5
 
6
6
 
7
+ ##
8
+
9
+
7
10
  @dc.dataclass(frozen=True)
8
11
  class Command:
9
12
  name: str
omdev/findimports.py CHANGED
@@ -13,6 +13,9 @@ import sys
13
13
  import typing as ta
14
14
 
15
15
 
16
+ ##
17
+
18
+
16
19
  _BUILTIN_MODULE_NAMES = frozenset([*sys.builtin_module_names, *sys.stdlib_module_names])
17
20
 
18
21
 
@@ -78,6 +81,9 @@ def get_import_deps(imps: set[str]) -> set[str]:
78
81
  return {i for i in eimps if whichmod(i) != 'builtin'}
79
82
 
80
83
 
84
+ ##
85
+
86
+
81
87
  # @omlish-manifest
82
88
  _CLI_MODULE = {'$omdev.cli.types.CliModule': {
83
89
  'cmd_name': 'py/findimports',
omdev/imgur.py CHANGED
@@ -36,6 +36,9 @@ from .cli import CliModule
36
36
  from .home.secrets import load_secrets
37
37
 
38
38
 
39
+ ##
40
+
41
+
39
42
  @dc.dataclass(frozen=True)
40
43
  @msh.update_object_metadata(unknown_field='x')
41
44
  class ImageUploadData:
omdev/tokens/all.py CHANGED
@@ -14,6 +14,7 @@ from .utils import ( # noqa
14
14
  ignore_ws,
15
15
 
16
16
  split_lines,
17
+ split_lines_dense,
17
18
  join_toks,
18
19
  join_lines,
19
20
 
omdev/tokens/utils.py CHANGED
@@ -42,6 +42,15 @@ def split_lines(ts: Tokens) -> list[Tokens]:
42
42
  return [list(it) for g, it in itertools.groupby(ts, lambda t: t.line)]
43
43
 
44
44
 
45
+ def split_lines_dense(ts: Tokens) -> list[Tokens]:
46
+ lines: list[list[Token]] = []
47
+ for t in ts:
48
+ while len(lines) < (t.line or 0):
49
+ lines.append([])
50
+ lines[-1].append(t)
51
+ return lines # type: ignore[return-value]
52
+
53
+
45
54
  def join_toks(ts: Tokens) -> str:
46
55
  return ''.join(t.src for t in ts)
47
56
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omdev
3
- Version: 0.0.0.dev282
3
+ Version: 0.0.0.dev283
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.dev282
15
+ Requires-Dist: omlish==0.0.0.dev283
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=25.1; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -1,11 +1,12 @@
1
- omdev/.manifests.json,sha256=6ctfThA3b81KIbdc0sNzL63fepwPCfqzH7uRp0edxfc,10078
1
+ omdev/.manifests.json,sha256=gpOkgx7EEYTrLPBJ-QnaUrW0fpWe9Lj6T3Wsye9wHgg,10325
2
2
  omdev/__about__.py,sha256=TeZN9riO-ekcaVodONcH5Es3OsQwWS7lu_dQHdzY_t4,1231
3
3
  omdev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- omdev/bracepy.py,sha256=I8EdqtDvxzAi3I8TuMEW-RBfwXfqKbwp06CfOdj3L1o,2743
5
- omdev/classdot.py,sha256=YOvgy6x295I_8NKBbBlRVd3AN7Osirm_Lqt4Wj0j9rY,1631
6
- omdev/cmake.py,sha256=oBAp1K8h-iCDd9uCn-OpNpZ6n36oYFkWLIiTyQw4irU,4573
7
- omdev/findimports.py,sha256=2t8QP852saEEJFeXySEzhi_nxRSxghlkXz2jVdvy08M,2392
8
- omdev/imgur.py,sha256=Uyz8nkORlhfXXK5Sty16tX8ro8s-b7LrxjOECv4_sB0,3005
4
+ omdev/attrdocs.py,sha256=XGY87xd9FZJqzGI8V9g4sSeQMWYu7oHD_klzC8YwZhk,4528
5
+ omdev/bracepy.py,sha256=PPPoTMj4FJ5Lk3GGPEEWBGU7Kl1eCJBApSJnRvRj2Ms,2753
6
+ omdev/classdot.py,sha256=Gmw4pFEFSnm6HBz65dI5-J8hNH1BSYgH_vsMcYKzbB4,1636
7
+ omdev/cmake.py,sha256=9rfSvFHPmKDj9ngvfDB2vK8O-xO_ZwUm7hMKLWA-yOw,4578
8
+ omdev/findimports.py,sha256=CDorwWr9hdIGnV-gvYQykdiz9hEsu8JrEZAF5sD_89w,2402
9
+ omdev/imgur.py,sha256=TkjK_M4nDarEmbP-FhVkt_VzSY2jHkZnKGnhnZ1zJAs,3010
9
10
  omdev/pip.py,sha256=PqzAWDO_CbiZvXzJAZcCkFqWynUDls1jIgBWlrswQyA,2012
10
11
  omdev/tagstrings.py,sha256=zIP7nzcsZf5te0lphu6k36ND_cOvNFRg00neoTcoCs8,5484
11
12
  omdev/amalg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -219,9 +220,9 @@ omdev/scripts/pyproject.py,sha256=dcWEUuHsE8_zIJ26s8MMlPlFgJzlE49kVhh2sQLDlKQ,26
219
220
  omdev/scripts/slowcat.py,sha256=lssv4yrgJHiWfOiHkUut2p8E8Tq32zB-ujXESQxFFHY,2728
220
221
  omdev/scripts/tmpexec.py,sha256=WTYcf56Tj2qjYV14AWmV8SfT0u6Y8eIU6cKgQRvEK3c,1442
221
222
  omdev/tokens/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
222
- omdev/tokens/all.py,sha256=4t_3NnU-ph_ehyC3XLB_J_lIda7KD1Xvc7rKexOVBAo,686
223
+ omdev/tokens/all.py,sha256=YT7d-jrEssJBCTC8ljVcQT7BPrCW_r1JCmE8OFzbgFg,709
223
224
  omdev/tokens/tokenizert.py,sha256=-KM5ajybESWCMtqxSm_5ktyu8s-p1MdTgYA4ungyrkM,7840
224
- omdev/tokens/utils.py,sha256=DJA2jsDzrtQxnO0bdkUk1-GmenX4ECugdhl1xOBe7QI,1448
225
+ omdev/tokens/utils.py,sha256=HN3nZhaZ0Fc7PxuUWLIMIm-l7jTh3R83-1dULkX9i2g,1698
225
226
  omdev/tools/__init__.py,sha256=iVJAOQ0viGTQOm0DLX4uZLro-9jOioYJGLg9s0kDx1A,78
226
227
  omdev/tools/cloc.py,sha256=jYlMHBae9oGKN4VKeBGuqjiQNcM2be7KIoTF0oNwx_I,5205
227
228
  omdev/tools/diff.py,sha256=_ThKWXFE-bG5SPDYNs8GqstEUPzL_PTWb03nJN0laLg,515
@@ -254,9 +255,9 @@ omdev/tools/json/rendering.py,sha256=tMcjOW5edfozcMSTxxvF7WVTsbYLoe9bCKFh50qyaGw
254
255
  omdev/tools/pawk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
255
256
  omdev/tools/pawk/__main__.py,sha256=VCqeRVnqT1RPEoIrqHFSu4PXVMg4YEgF4qCQm90-eRI,66
256
257
  omdev/tools/pawk/pawk.py,sha256=zsEkfQX0jF5bn712uqPAyBSdJt2dno1LH2oeSMNfXQI,11424
257
- omdev-0.0.0.dev282.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
258
- omdev-0.0.0.dev282.dist-info/METADATA,sha256=r2Lfs-wg3GiySKVrdY6UMsqfmklwBh7KSNswxGHChU0,1588
259
- omdev-0.0.0.dev282.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
260
- omdev-0.0.0.dev282.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
261
- omdev-0.0.0.dev282.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
262
- omdev-0.0.0.dev282.dist-info/RECORD,,
258
+ omdev-0.0.0.dev283.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
259
+ omdev-0.0.0.dev283.dist-info/METADATA,sha256=deF-r5kF_saAx6QkRAyDHWoQQlItNcTo9ejJRCZRkyc,1588
260
+ omdev-0.0.0.dev283.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
261
+ omdev-0.0.0.dev283.dist-info/entry_points.txt,sha256=dHLXFmq5D9B8qUyhRtFqTGWGxlbx3t5ejedjrnXNYLU,33
262
+ omdev-0.0.0.dev283.dist-info/top_level.txt,sha256=1nr7j30fEWgLYHW3lGR9pkdHkb7knv1U1ES1XRNVQ6k,6
263
+ omdev-0.0.0.dev283.dist-info/RECORD,,