symbex 0.3__tar.gz → 0.3.2__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: symbex
3
- Version: 0.3
3
+ Version: 0.3.2
4
4
  Summary: Find the Python code for specified symbols
5
5
  Home-page: https://github.com/simonw/symbex
6
6
  Author: Simon Willison
@@ -132,7 +132,7 @@ cog.out(
132
132
  # File: symbex/cli.py Line: 37
133
133
  def cli(symbols, files, directories, signatures, silent)
134
134
 
135
- # File: symbex/lib.py Line: 150
135
+ # File: symbex/lib.py Line: 161
136
136
  def class_definition(class_def)
137
137
 
138
138
  # File: symbex/lib.py Line: 32
@@ -117,7 +117,7 @@ cog.out(
117
117
  # File: symbex/cli.py Line: 37
118
118
  def cli(symbols, files, directories, signatures, silent)
119
119
 
120
- # File: symbex/lib.py Line: 150
120
+ # File: symbex/lib.py Line: 161
121
121
  def class_definition(class_def)
122
122
 
123
123
  # File: symbex/lib.py Line: 32
@@ -1,7 +1,7 @@
1
1
  from setuptools import setup
2
2
  import os
3
3
 
4
- VERSION = "0.3"
4
+ VERSION = "0.3.2"
5
5
 
6
6
 
7
7
  def get_long_description():
@@ -1,5 +1,5 @@
1
1
  import fnmatch
2
- from ast import literal_eval, parse, AST, FunctionDef, ClassDef
2
+ from ast import literal_eval, parse, AST, AsyncFunctionDef, FunctionDef, ClassDef
3
3
  from itertools import zip_longest
4
4
  import textwrap
5
5
  from typing import Iterable, List, Optional, Tuple
@@ -13,7 +13,7 @@ def find_symbol_nodes(
13
13
  matches = []
14
14
  module = parse(code)
15
15
  for node in module.body:
16
- if not isinstance(node, (ClassDef, FunctionDef)):
16
+ if not isinstance(node, (ClassDef, FunctionDef, AsyncFunctionDef)):
17
17
  continue
18
18
  name = getattr(node, "name", None)
19
19
  if match(name, symbols):
@@ -21,7 +21,7 @@ def find_symbol_nodes(
21
21
  # If it's a class search its methods too
22
22
  if isinstance(node, ClassDef):
23
23
  for child in node.body:
24
- if isinstance(child, FunctionDef):
24
+ if isinstance(child, (FunctionDef, AsyncFunctionDef)):
25
25
  qualified_name = f"{name}.{child.name}"
26
26
  if match(qualified_name, symbols):
27
27
  matches.append((child, name))
@@ -37,7 +37,7 @@ def code_for_node(
37
37
  start = None
38
38
  end = None
39
39
  if signatures:
40
- if isinstance(node, FunctionDef):
40
+ if isinstance(node, (FunctionDef, AsyncFunctionDef)):
41
41
  definition, lineno = function_definition(node), node.lineno
42
42
  if class_name:
43
43
  definition = " " + definition
@@ -109,7 +109,14 @@ def function_definition(function_node: AST):
109
109
  # if defaults has 2 and args has 3 then those
110
110
  # defaults correspond to the last two args
111
111
  defaults = [None] * (len(all_args) - len(function_node.args.defaults))
112
- defaults.extend(literal_eval(default) for default in function_node.args.defaults)
112
+ for default in function_node.args.defaults:
113
+ try:
114
+ value = literal_eval(default)
115
+ if isinstance(value, str):
116
+ value = f'"{value}"'
117
+ except ValueError:
118
+ value = getattr(default, "id", "...")
119
+ defaults.append(value)
113
120
 
114
121
  arguments = []
115
122
 
@@ -144,7 +151,11 @@ def function_definition(function_node: AST):
144
151
  # None shows as returns.value is None
145
152
  return_annotation = " -> None"
146
153
 
147
- return f"def {function_name}({arguments_str}){return_annotation}"
154
+ def_ = "def "
155
+ if isinstance(function_node, AsyncFunctionDef):
156
+ def_ = "async def "
157
+
158
+ return f"{def_}{function_name}({arguments_str}){return_annotation}"
148
159
 
149
160
 
150
161
  def class_definition(class_def):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: symbex
3
- Version: 0.3
3
+ Version: 0.3.2
4
4
  Summary: Find the Python code for specified symbols
5
5
  Home-page: https://github.com/simonw/symbex
6
6
  Author: Simon Willison
@@ -132,7 +132,7 @@ cog.out(
132
132
  # File: symbex/cli.py Line: 37
133
133
  def cli(symbols, files, directories, signatures, silent)
134
134
 
135
- # File: symbex/lib.py Line: 150
135
+ # File: symbex/lib.py Line: 161
136
136
  def class_definition(class_def)
137
137
 
138
138
  # File: symbex/lib.py Line: 32
@@ -11,7 +11,7 @@ def directory_full_of_code(tmpdir):
11
11
  for path, content in (
12
12
  ("foo.py", "def foo1():\n pass\n\n@decorated\ndef foo2():\n pass\n\n"),
13
13
  ("bar.py", "class BarClass:\n pass\n\n"),
14
- ("nested/baz.py", "def baz():\n pass\n\n"),
14
+ ("nested/baz.py", 'def baz(delimiter=", ", type=str):\n pass\n\n'),
15
15
  ("nested/error.py", "def baz_error()" + "bug:\n pass\n\n"),
16
16
  (
17
17
  "methods.py",
@@ -26,6 +26,19 @@ def directory_full_of_code(tmpdir):
26
26
  """
27
27
  ),
28
28
  ),
29
+ (
30
+ "async.py",
31
+ textwrap.dedent(
32
+ """
33
+ async def async_func(a, b, c):
34
+ pass
35
+
36
+ class MyAsyncClass:
37
+ async def async_method(a, b, c):
38
+ pass
39
+ """
40
+ ).strip(),
41
+ ),
29
42
  ):
30
43
  p = pathlib.Path(tmpdir / path)
31
44
  p.parent.mkdir(parents=True, exist_ok=True)
@@ -47,17 +60,21 @@ def directory_full_of_code(tmpdir):
47
60
  ),
48
61
  (
49
62
  ["baz", "--silent"],
50
- "# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n",
63
+ '# File: nested/baz.py Line: 1\ndef baz(delimiter=", ", type=str):\n pass\n\n',
64
+ ),
65
+ (
66
+ ["async_func", "--silent"],
67
+ "# File: async.py Line: 1\nasync def async_func(a, b, c):\n pass\n\n",
51
68
  ),
52
69
  # The -f option
53
70
  (
54
71
  ["baz", "-f", "nested/baz.py", "--silent"],
55
- "# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n",
72
+ '# File: nested/baz.py Line: 1\ndef baz(delimiter=", ", type=str):\n pass\n\n',
56
73
  ),
57
74
  # The -d option
58
75
  (
59
76
  ["baz", "-d", "nested", "--silent"],
60
- "# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n",
77
+ '# File: nested/baz.py Line: 1\ndef baz(delimiter=", ", type=str):\n pass\n\n',
61
78
  ),
62
79
  # Classes
63
80
  (
@@ -96,6 +113,15 @@ def directory_full_of_code(tmpdir):
96
113
  " pass\n"
97
114
  "\n",
98
115
  ),
116
+ (
117
+ ["*.async_method", "--silent"],
118
+ (
119
+ "# File: async.py Class: MyAsyncClass Line: 5\n"
120
+ " async def async_method(a, b, c):\n"
121
+ " pass\n"
122
+ "\n"
123
+ ),
124
+ ),
99
125
  ),
100
126
  )
101
127
  def test_fixture(directory_full_of_code, monkeypatch, args, expected):
@@ -118,7 +144,10 @@ def test_fixture(directory_full_of_code, monkeypatch, args, expected):
118
144
  "def foo2()",
119
145
  ),
120
146
  (["BarClass", "--silent"], "# File: bar.py Line: 1\n" "class BarClass"),
121
- (["baz", "--silent"], ("# File: nested/baz.py Line: 1\n" "def baz()")),
147
+ (
148
+ ["baz", "--silent"],
149
+ ("# File: nested/baz.py Line: 1\n" 'def baz(delimiter=", ", type=str)'),
150
+ ),
122
151
  ),
123
152
  )
124
153
  def test_symbex_symbols(directory_full_of_code, monkeypatch, args, expected):
@@ -136,8 +165,11 @@ def test_errors(directory_full_of_code, monkeypatch):
136
165
  monkeypatch.chdir(directory_full_of_code)
137
166
  result = runner.invoke(cli, ["baz"], catch_exceptions=False)
138
167
  assert result.exit_code == 0
139
- assert result.stdout == (
140
- "# File: nested/baz.py Line: 1\n" "def baz():\n" " pass\n\n"
168
+ expected = (
169
+ "# File: nested/baz.py Line: 1\n"
170
+ 'def baz(delimiter=", ", type=str):\n'
171
+ " pass\n\n"
141
172
  )
173
+ assert result.stdout == expected
142
174
  # This differs between different Python versions
143
175
  assert result.stderr.startswith("# Syntax error in nested/error.py:")
@@ -20,6 +20,7 @@ def symbols_text():
20
20
  (
21
21
  ("func_no_args", "def func_no_args()"),
22
22
  ("func_positional_args", "def func_positional_args(a, b, c)"),
23
+ ("async_func", "async def async_func(a, b, c)"),
23
24
  ("func_default_args", "def func_default_args(a, b=2, c=3)"),
24
25
  ("func_arbitrary_positional_args", "def func_arbitrary_positional_args(*args)"),
25
26
  ("func_arbitrary_keyword_args", "def func_arbitrary_keyword_args(**kwargs)"),
@@ -45,3 +46,20 @@ def test_symbols(name, expected, symbols_text):
45
46
  )
46
47
  # Special case to ensure we don't get ClassNoBase()
47
48
  assert "ClassNoBase()" not in symbols_text
49
+
50
+
51
+ def test_method_symbols():
52
+ runner = CliRunner()
53
+ args = [
54
+ "*.async*",
55
+ "-s",
56
+ "-f",
57
+ str(pathlib.Path(__file__).parent / "example_symbols.py"),
58
+ ]
59
+ result = runner.invoke(cli, args, catch_exceptions=False)
60
+ assert result.exit_code == 0
61
+ assert result.stdout == (
62
+ "# File: tests/example_symbols.py Class: ClassWithMethods Line: 88\n"
63
+ " async def async_method(a, b, c)\n"
64
+ "\n"
65
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes