symbex 1.2__py3-none-any.whl → 1.3.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|