symbex 1.2__py3-none-any.whl → 1.3.1__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.
- symbex/cli.py +42 -0
- symbex/lib.py +2 -2
- {symbex-1.2.dist-info → symbex-1.3.1.dist-info}/METADATA +45 -19
- symbex-1.3.1.dist-info/RECORD +10 -0
- {symbex-1.2.dist-info → symbex-1.3.1.dist-info}/WHEEL +1 -1
- symbex-1.2.dist-info/RECORD +0 -10
- {symbex-1.2.dist-info → symbex-1.3.1.dist-info}/LICENSE +0 -0
- {symbex-1.2.dist-info → symbex-1.3.1.dist-info}/entry_points.txt +0 -0
- {symbex-1.2.dist-info → symbex-1.3.1.dist-info}/top_level.txt +0 -0
symbex/cli.py
CHANGED
@@ -120,6 +120,21 @@ from .lib import (
|
|
120
120
|
is_flag=True,
|
121
121
|
help="Filter functions without docstrings",
|
122
122
|
)
|
123
|
+
@click.option(
|
124
|
+
"--public",
|
125
|
+
is_flag=True,
|
126
|
+
help="Filter for symbols without a _ prefix",
|
127
|
+
)
|
128
|
+
@click.option(
|
129
|
+
"--private",
|
130
|
+
is_flag=True,
|
131
|
+
help="Filter for symbols with a _ prefix",
|
132
|
+
)
|
133
|
+
@click.option(
|
134
|
+
"--dunder",
|
135
|
+
is_flag=True,
|
136
|
+
help="Filter for symbols matching __*__",
|
137
|
+
)
|
123
138
|
@click.option(
|
124
139
|
"--typed",
|
125
140
|
is_flag=True,
|
@@ -174,6 +189,9 @@ def cli(
|
|
174
189
|
class_,
|
175
190
|
documented,
|
176
191
|
undocumented,
|
192
|
+
public,
|
193
|
+
private,
|
194
|
+
dunder,
|
177
195
|
typed,
|
178
196
|
untyped,
|
179
197
|
partially_typed,
|
@@ -234,6 +252,11 @@ def cli(
|
|
234
252
|
# This is a replacement implementation
|
235
253
|
return a + b + 3
|
236
254
|
" | symbex my_function --replace
|
255
|
+
|
256
|
+
\b
|
257
|
+
# Replace my_function with the output of a command:
|
258
|
+
symbex first_function --rexec "sed 's/^/# /'"
|
259
|
+
# This uses sed to comment out the function body
|
237
260
|
"""
|
238
261
|
if modules:
|
239
262
|
module_dirs = []
|
@@ -281,6 +304,9 @@ def cli(
|
|
281
304
|
class_,
|
282
305
|
documented,
|
283
306
|
undocumented,
|
307
|
+
public,
|
308
|
+
private,
|
309
|
+
dunder,
|
284
310
|
typed,
|
285
311
|
untyped,
|
286
312
|
partially_typed,
|
@@ -312,6 +338,9 @@ def cli(
|
|
312
338
|
class_,
|
313
339
|
documented,
|
314
340
|
undocumented,
|
341
|
+
public,
|
342
|
+
private,
|
343
|
+
dunder,
|
315
344
|
typed,
|
316
345
|
untyped,
|
317
346
|
partially_typed,
|
@@ -347,6 +376,9 @@ def cli(
|
|
347
376
|
class_,
|
348
377
|
documented,
|
349
378
|
undocumented,
|
379
|
+
public,
|
380
|
+
private,
|
381
|
+
dunder,
|
350
382
|
typed,
|
351
383
|
untyped,
|
352
384
|
partially_typed,
|
@@ -371,6 +403,12 @@ def cli(
|
|
371
403
|
return False
|
372
404
|
if undocumented and ast.get_docstring(node):
|
373
405
|
return False
|
406
|
+
if public and node.name.startswith("_") and not is_dunder(node.name):
|
407
|
+
return False
|
408
|
+
if private and (is_dunder(node.name) or not node.name.startswith("_")):
|
409
|
+
return False
|
410
|
+
if dunder and not is_dunder(node.name):
|
411
|
+
return False
|
374
412
|
summary = type_summary(node)
|
375
413
|
# if no summary, type filters all fail
|
376
414
|
if not summary and (
|
@@ -499,3 +537,7 @@ def is_subpath(path: pathlib.Path, parent: pathlib.Path) -> bool:
|
|
499
537
|
return True
|
500
538
|
except ValueError:
|
501
539
|
return False
|
540
|
+
|
541
|
+
|
542
|
+
def is_dunder(name):
|
543
|
+
return name.startswith("__") and name.endswith("__")
|
symbex/lib.py
CHANGED
@@ -169,7 +169,7 @@ def function_definition(function_node: AST):
|
|
169
169
|
if isinstance(function_node, AsyncFunctionDef):
|
170
170
|
def_ = "async def "
|
171
171
|
|
172
|
-
return f"{def_}{function_name}({arguments_str}){return_annotation}"
|
172
|
+
return f"{def_}{function_name}({arguments_str}){return_annotation}:"
|
173
173
|
|
174
174
|
|
175
175
|
def class_definition(class_def):
|
@@ -201,7 +201,7 @@ def class_definition(class_def):
|
|
201
201
|
if signature:
|
202
202
|
signature = f"({signature})"
|
203
203
|
|
204
|
-
class_definition = f"class {class_def.name}{signature}"
|
204
|
+
class_definition = f"class {class_def.name}{signature}:"
|
205
205
|
|
206
206
|
return class_definition
|
207
207
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: symbex
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.1
|
4
4
|
Summary: Find the Python code for specified symbols
|
5
5
|
Home-page: https://github.com/simonw/symbex
|
6
6
|
Author: Simon Willison
|
@@ -121,6 +121,9 @@ The following filters are available:
|
|
121
121
|
- `--unasync` - only non-async functions
|
122
122
|
- `--documented` - functions/classes that have a docstring
|
123
123
|
- `--undocumented` - functions/classes that do not have a docstring
|
124
|
+
- `--public` - functions/classes that are public - don't have a `_name` prefix (or are `__*__` methods)
|
125
|
+
- `--private` - functions/classes that are private - have a `_name` prefix and are not `__*__`
|
126
|
+
- `--dunder` - functions matching `__*__` - this should usually be used with `*.*` to find all dunder methods
|
124
127
|
- `--typed` - functions that have at least one type annotation
|
125
128
|
- `--untyped` - functions that have no type annotations
|
126
129
|
- `--partially-typed` - functions that have some type annotations but not all
|
@@ -141,6 +144,12 @@ This example shows the full source code of every class method in the Python stan
|
|
141
144
|
symbex --fully-typed --no-init '*.*' --stdlib
|
142
145
|
```
|
143
146
|
|
147
|
+
To find all public functions and methods that lack documentation, just showing the signature of each one:
|
148
|
+
|
149
|
+
```bash
|
150
|
+
symbex '*' '*.*' --public --undocumented --signatures
|
151
|
+
```
|
152
|
+
|
144
153
|
### Example output
|
145
154
|
|
146
155
|
In a fresh checkout of [Datasette](https://github.com/simonw/datasette) I ran this command:
|
@@ -196,40 +205,40 @@ cog.out(
|
|
196
205
|
]]] -->
|
197
206
|
```python
|
198
207
|
# File: symbex/lib.py Line: 107
|
199
|
-
def function_definition(function_node: AST)
|
208
|
+
def function_definition(function_node: AST):
|
200
209
|
|
201
210
|
# File: symbex/lib.py Line: 13
|
202
|
-
def find_symbol_nodes(code: str, filename: str, symbols: Iterable[str]) -> List[Tuple[(AST, Optional[str])]]
|
211
|
+
def find_symbol_nodes(code: str, filename: str, symbols: Iterable[str]) -> List[Tuple[(AST, Optional[str])]]:
|
203
212
|
|
204
213
|
# File: symbex/lib.py Line: 175
|
205
|
-
def class_definition(class_def)
|
214
|
+
def class_definition(class_def):
|
206
215
|
|
207
216
|
# File: symbex/lib.py Line: 209
|
208
|
-
def annotation_definition(annotation: AST) -> str
|
217
|
+
def annotation_definition(annotation: AST) -> str:
|
209
218
|
|
210
219
|
# File: symbex/lib.py Line: 227
|
211
|
-
def read_file(path)
|
220
|
+
def read_file(path):
|
212
221
|
|
213
222
|
# File: symbex/lib.py Line: 253
|
214
|
-
class TypeSummary
|
223
|
+
class TypeSummary:
|
215
224
|
|
216
225
|
# File: symbex/lib.py Line: 258
|
217
|
-
def type_summary(node: AST) -> Optional[TypeSummary]
|
226
|
+
def type_summary(node: AST) -> Optional[TypeSummary]:
|
218
227
|
|
219
228
|
# File: symbex/lib.py Line: 304
|
220
|
-
def quoted_string(s)
|
229
|
+
def quoted_string(s):
|
221
230
|
|
222
231
|
# File: symbex/lib.py Line: 315
|
223
|
-
def import_line_for_function(function_name: str, filepath: str, possible_root_dirs: List[str]) -> str
|
232
|
+
def import_line_for_function(function_name: str, filepath: str, possible_root_dirs: List[str]) -> str:
|
224
233
|
|
225
234
|
# File: symbex/lib.py Line: 37
|
226
|
-
def code_for_node(code: str, node: AST, class_name: str, signatures: bool, docstrings: bool) -> Tuple[(str, int)]
|
235
|
+
def code_for_node(code: str, node: AST, class_name: str, signatures: bool, docstrings: bool) -> Tuple[(str, int)]:
|
227
236
|
|
228
237
|
# File: symbex/lib.py Line: 71
|
229
|
-
def add_docstring(definition: str, node: AST, docstrings: bool, is_method: bool) -> str
|
238
|
+
def add_docstring(definition: str, node: AST, docstrings: bool, is_method: bool) -> str:
|
230
239
|
|
231
240
|
# File: symbex/lib.py Line: 82
|
232
|
-
def match(name: str, symbols: Iterable[str]) -> bool
|
241
|
+
def match(name: str, symbols: Iterable[str]) -> bool:
|
233
242
|
```
|
234
243
|
<!-- [[[end]]] -->
|
235
244
|
This can be combined with other options, or you can run `symbex -s` to see every symbol in the current directory and its subdirectories.
|
@@ -251,7 +260,7 @@ cog.out(
|
|
251
260
|
```python
|
252
261
|
# File: symbex/lib.py Line: 82
|
253
262
|
# from symbex.lib import match
|
254
|
-
def match(name: str, symbols: Iterable[str]) -> bool
|
263
|
+
def match(name: str, symbols: Iterable[str]) -> bool:
|
255
264
|
```
|
256
265
|
<!-- [[[end]]] -->
|
257
266
|
To suppress the `# File: ...` comments, use `--no-file` or `-n`.
|
@@ -271,7 +280,7 @@ cog.out(
|
|
271
280
|
]]] -->
|
272
281
|
```python
|
273
282
|
# from symbex.lib import match
|
274
|
-
def match(name: str, symbols: Iterable[str]) -> bool
|
283
|
+
def match(name: str, symbols: Iterable[str]) -> bool:
|
275
284
|
```
|
276
285
|
<!-- [[[end]]] -->
|
277
286
|
|
@@ -288,7 +297,7 @@ cog.out(
|
|
288
297
|
]]] -->
|
289
298
|
```python
|
290
299
|
# File: symbex/lib.py Line: 82
|
291
|
-
def match(name: str, symbols: Iterable[str]) -> bool
|
300
|
+
def match(name: str, symbols: Iterable[str]) -> bool:
|
292
301
|
"Returns True if name matches any of the symbols, resolving wildcards"
|
293
302
|
```
|
294
303
|
<!-- [[[end]]] -->
|
@@ -405,14 +414,24 @@ def second_function(a: int, b: int) -> int:
|
|
405
414
|
|
406
415
|
The `--check` option causes `symbex` to return a non-zero exit code if any matches are found for your query.
|
407
416
|
|
408
|
-
You can use this in CI to guard against things like functions being added without documentation:
|
417
|
+
You can use this in CI to guard against things like public functions being added without documentation:
|
409
418
|
|
410
419
|
```bash
|
411
|
-
symbex --function --undocumented --check
|
420
|
+
symbex --function --public --undocumented --check
|
412
421
|
```
|
413
422
|
This will fail silently but set a `1` exit code if there are any undocumented functions.
|
414
423
|
|
415
|
-
|
424
|
+
Using this as a step in a CI tool such as GitHub Actions should result in a test failure.
|
425
|
+
|
426
|
+
Run this to see the exit code from the last command:
|
427
|
+
```bash
|
428
|
+
echo $?
|
429
|
+
```
|
430
|
+
|
431
|
+
`--check` will not output anything by default. Add `--count` to output a count of matching symbols, or `-s/--signatures` to output the signatures of the matching symbols, for example:
|
432
|
+
```bash
|
433
|
+
symbex --function --public --undocumented --check --count
|
434
|
+
```
|
416
435
|
|
417
436
|
## Similar tools
|
418
437
|
|
@@ -471,6 +490,10 @@ Usage: symbex [OPTIONS] [SYMBOLS]...
|
|
471
490
|
return a + b + 3
|
472
491
|
" | symbex my_function --replace
|
473
492
|
|
493
|
+
# Replace my_function with the output of a command:
|
494
|
+
symbex first_function --rexec "sed 's/^/# /'"
|
495
|
+
# This uses sed to comment out the function body
|
496
|
+
|
474
497
|
Options:
|
475
498
|
--version Show the version and exit.
|
476
499
|
-f, --file FILE Files to search
|
@@ -491,6 +514,9 @@ Options:
|
|
491
514
|
--class Filter classes
|
492
515
|
--documented Filter functions with docstrings
|
493
516
|
--undocumented Filter functions without docstrings
|
517
|
+
--public Filter for symbols without a _ prefix
|
518
|
+
--private Filter for symbols with a _ prefix
|
519
|
+
--dunder Filter for symbols matching __*__
|
494
520
|
--typed Filter functions with type annotations
|
495
521
|
--untyped Filter functions without type annotations
|
496
522
|
--partially-typed Filter functions with partial type annotations
|
@@ -0,0 +1,10 @@
|
|
1
|
+
symbex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
symbex/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
|
3
|
+
symbex/cli.py,sha256=uuP28l7qAWWPE3b0u2HLM1ID89m402EBNgYOhcejdgw,14974
|
4
|
+
symbex/lib.py,sha256=CiKKOOyc6Ne_7igzNItMZpa5I6o12LEbIPrQU9al7Ro,11436
|
5
|
+
symbex-1.3.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
6
|
+
symbex-1.3.1.dist-info/METADATA,sha256=1oJBLr7_LdzFltBb5cMMCttPFo-XZhFGOzK_1MOQ9ls,19263
|
7
|
+
symbex-1.3.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
8
|
+
symbex-1.3.1.dist-info/entry_points.txt,sha256=YgMSEfEGqNMHM9RysFObH8lkQKVZKyymKLnXbVue_Uk,42
|
9
|
+
symbex-1.3.1.dist-info/top_level.txt,sha256=qwle8HjAaYgpdMIHlJcTcN4gaG4wmDqUvkt54beTBTs,7
|
10
|
+
symbex-1.3.1.dist-info/RECORD,,
|
symbex-1.2.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
symbex/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
symbex/__main__.py,sha256=8hDtWlaFZK24KhfNq_ZKgtXqYHsDQDetukOCMlsbW0Q,59
|
3
|
-
symbex/cli.py,sha256=6jts3COuZSwfK_HbEtptUs5IRC7VP5woGQHJTkm_CFk,13881
|
4
|
-
symbex/lib.py,sha256=xgn-tiLoeIvu2iYpwuB7fvDK6epBBd5VHSc2Y7wRQsk,11434
|
5
|
-
symbex-1.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
6
|
-
symbex-1.2.dist-info/METADATA,sha256=v2zGtiB2GYz7Tc23UJiPvcK_AUFGJuSztikZiMvVFPE,18139
|
7
|
-
symbex-1.2.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
8
|
-
symbex-1.2.dist-info/entry_points.txt,sha256=YgMSEfEGqNMHM9RysFObH8lkQKVZKyymKLnXbVue_Uk,42
|
9
|
-
symbex-1.2.dist-info/top_level.txt,sha256=qwle8HjAaYgpdMIHlJcTcN4gaG4wmDqUvkt54beTBTs,7
|
10
|
-
symbex-1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|