From cd7eae3370213ec3a6ffaf5ebb749e59e03b9d6c Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 2 Sep 2023 13:48:21 -0700 Subject: [PATCH] Include trailing colons in signatures, closes #39 --- README.md | 30 +++++++++++++++--------------- symbex/lib.py | 4 ++-- tests/test_filters.py | 4 ++-- tests/test_symbex.py | 10 +++++----- tests/test_symbols.py | 16 ++++++++-------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 21af163..1095130 100644 --- a/README.md +++ b/README.md @@ -184,40 +184,40 @@ cog.out( ]]] --> ```python # File: symbex/lib.py Line: 107 -def function_definition(function_node: AST) +def function_definition(function_node: AST): # File: symbex/lib.py Line: 13 -def find_symbol_nodes(code: str, filename: str, symbols: Iterable[str]) -> List[Tuple[(AST, Optional[str])]] +def find_symbol_nodes(code: str, filename: str, symbols: Iterable[str]) -> List[Tuple[(AST, Optional[str])]]: # File: symbex/lib.py Line: 175 -def class_definition(class_def) +def class_definition(class_def): # File: symbex/lib.py Line: 209 -def annotation_definition(annotation: AST) -> str +def annotation_definition(annotation: AST) -> str: # File: symbex/lib.py Line: 227 -def read_file(path) +def read_file(path): # File: symbex/lib.py Line: 253 -class TypeSummary +class TypeSummary: # File: symbex/lib.py Line: 258 -def type_summary(node: AST) -> Optional[TypeSummary] +def type_summary(node: AST) -> Optional[TypeSummary]: # File: symbex/lib.py Line: 304 -def quoted_string(s) +def quoted_string(s): # File: symbex/lib.py Line: 315 -def import_line_for_function(function_name: str, filepath: str, possible_root_dirs: List[str]) -> str +def import_line_for_function(function_name: str, filepath: str, possible_root_dirs: List[str]) -> str: # File: symbex/lib.py Line: 37 -def code_for_node(code: str, node: AST, class_name: str, signatures: bool, docstrings: bool) -> Tuple[(str, int)] +def code_for_node(code: str, node: AST, class_name: str, signatures: bool, docstrings: bool) -> Tuple[(str, int)]: # File: symbex/lib.py Line: 71 -def add_docstring(definition: str, node: AST, docstrings: bool, is_method: bool) -> str +def add_docstring(definition: str, node: AST, docstrings: bool, is_method: bool) -> str: # File: symbex/lib.py Line: 82 -def match(name: str, symbols: Iterable[str]) -> bool +def match(name: str, symbols: Iterable[str]) -> bool: ``` This can be combined with other options, or you can run `symbex -s` to see every symbol in the current directory and its subdirectories. @@ -239,7 +239,7 @@ cog.out( ```python # File: symbex/lib.py Line: 82 # from symbex.lib import match -def match(name: str, symbols: Iterable[str]) -> bool +def match(name: str, symbols: Iterable[str]) -> bool: ``` To suppress the `# File: ...` comments, use `--no-file` or `-n`. @@ -259,7 +259,7 @@ cog.out( ]]] --> ```python # from symbex.lib import match -def match(name: str, symbols: Iterable[str]) -> bool +def match(name: str, symbols: Iterable[str]) -> bool: ``` @@ -276,7 +276,7 @@ cog.out( ]]] --> ```python # File: symbex/lib.py Line: 82 -def match(name: str, symbols: Iterable[str]) -> bool +def match(name: str, symbols: Iterable[str]) -> bool: "Returns True if name matches any of the symbols, resolving wildcards" ``` diff --git a/symbex/lib.py b/symbex/lib.py index 3f17ccd..e5b96fa 100644 --- a/symbex/lib.py +++ b/symbex/lib.py @@ -169,7 +169,7 @@ def function_definition(function_node: AST): if isinstance(function_node, AsyncFunctionDef): def_ = "async def " - return f"{def_}{function_name}({arguments_str}){return_annotation}" + return f"{def_}{function_name}({arguments_str}){return_annotation}:" def class_definition(class_def): @@ -201,7 +201,7 @@ def class_definition(class_def): if signature: signature = f"({signature})" - class_definition = f"class {class_def.name}{signature}" + class_definition = f"class {class_def.name}{signature}:" return class_definition diff --git a/tests/test_filters.py b/tests/test_filters.py index 63efa2d..d8cf22a 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -288,8 +288,8 @@ def test_filters(args, expected): for line in result.stdout.splitlines() if line.strip() and not line.startswith("# File:") ] - # We only match up to the opening "(" - defs = [line.split("(")[0] for line in lines] + # We only match up to the opening "(" or ":" + defs = [line.split("(")[0].split(":")[0] for line in lines] assert defs == expected # Test the --count option too diff --git a/tests/test_symbex.py b/tests/test_symbex.py index 3cb46e4..c9c8c4e 100644 --- a/tests/test_symbex.py +++ b/tests/test_symbex.py @@ -151,23 +151,23 @@ def test_fixture(directory_full_of_code, monkeypatch, args, expected): ( ["foo*", "--silent"], "# File: foo.py Line: 1\n" - "def foo1()\n" + "def foo1():\n" "\n" "# File: foo.py Line: 5\n" - "def foo2()", + "def foo2():", ), - (["BarClass", "--silent"], "# File: bar.py Line: 1\n" "class BarClass"), + (["BarClass", "--silent"], "# File: bar.py Line: 1\n" "class BarClass:"), ( ["baz", "--silent"], ( "# File: nested.py/x/baz.py Line: 1\n" - 'def baz(delimiter=", ", type=str)' + 'def baz(delimiter=", ", type=str):' ), ), # Test for the --module option ( ["-m", "pathlib", "Path", "--silent", "-in"], - ("# from pathlib import Path\nclass Path(PurePath)"), + ("# from pathlib import Path\nclass Path(PurePath):"), ), ), ) diff --git a/tests/test_symbols.py b/tests/test_symbols.py index f7de8d1..bb3ea54 100644 --- a/tests/test_symbols.py +++ b/tests/test_symbols.py @@ -69,7 +69,7 @@ def test_method_symbols(): assert result.exit_code == 0 assert result.stdout == ( "# File: tests/example_symbols.py Class: ClassWithMethods Line: 91\n" - " async def async_method(a, b, c)\n" + " async def async_method(a, b, c):\n" "\n" ) @@ -88,20 +88,20 @@ def test_docstrings(): assert result.exit_code == 0 expected = """ # File: tests/example_symbols.py Line: X -def func_no_args() +def func_no_args(): "This has a single line docstring" # File: tests/example_symbols.py Line: X -def func_positional_args(a, b, c) +def func_positional_args(a, b, c): \"\"\"This has a multi-line docstring\"\"\" # File: tests/example_symbols.py Class: ClassForTypedTests Line: X - def method_fully_typed(self, a: int, b: str) -> bool + def method_fully_typed(self, a: int, b: str) -> bool: "Single line" # File: tests/example_symbols.py Class: ClassForTypedTests Line: X - def method_partially_typed(self, a: int, b) -> bool + def method_partially_typed(self, a: int, b) -> bool: \"\"\"Multiple lines\"\"\" """.strip() @@ -126,15 +126,15 @@ def test_imports(no_file): expected = """ # File: tests/example_symbols.py Line: 28 # from example_symbols import func_arbitrary_positional_args -def func_arbitrary_positional_args(*args) +def func_arbitrary_positional_args(*args): # File: tests/example_symbols.py Line: 33 # from example_symbols import func_arbitrary_keyword_args -def func_arbitrary_keyword_args(**kwargs) +def func_arbitrary_keyword_args(**kwargs): # File: tests/example_symbols.py Line: 38 # from example_symbols import func_arbitrary_args -def func_arbitrary_args(*args, **kwargs) +def func_arbitrary_args(*args, **kwargs): """.strip() if no_file: lines = expected.split("\n")