symbex 0.2__tar.gz → 0.2.1__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {symbex-0.2/symbex.egg-info → symbex-0.2.1}/PKG-INFO +9 -1
- {symbex-0.2 → symbex-0.2.1}/README.md +8 -0
- {symbex-0.2 → symbex-0.2.1}/setup.py +1 -1
- {symbex-0.2 → symbex-0.2.1}/symbex/cli.py +19 -4
- {symbex-0.2 → symbex-0.2.1/symbex.egg-info}/PKG-INFO +9 -1
- symbex-0.2.1/tests/test_symbex.py +68 -0
- symbex-0.2/tests/test_symbex.py +0 -38
- {symbex-0.2 → symbex-0.2.1}/LICENSE +0 -0
- {symbex-0.2 → symbex-0.2.1}/setup.cfg +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex/__init__.py +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex/__main__.py +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex/lib.py +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex.egg-info/SOURCES.txt +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex.egg-info/dependency_links.txt +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex.egg-info/entry_points.txt +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex.egg-info/requires.txt +0 -0
- {symbex-0.2 → symbex-0.2.1}/symbex.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: symbex
|
3
|
-
Version: 0.2
|
3
|
+
Version: 0.2.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
|
@@ -54,6 +54,14 @@ To search within a specific directory and all of its subdirectories, use the `-d
|
|
54
54
|
```bash
|
55
55
|
symbex Database -d ~/projects/datasette
|
56
56
|
```
|
57
|
+
If `symbex` encounters any Python code that it cannot parse, it will print a warning message and continue searching:
|
58
|
+
```
|
59
|
+
# Syntax error in path/badcode.py: expected ':' (<unknown>, line 1)
|
60
|
+
```
|
61
|
+
Pass `--silent` to suppress these warnings:
|
62
|
+
```bash
|
63
|
+
symbex MyClass --silent
|
64
|
+
```
|
57
65
|
|
58
66
|
## Example output
|
59
67
|
|
@@ -39,6 +39,14 @@ To search within a specific directory and all of its subdirectories, use the `-d
|
|
39
39
|
```bash
|
40
40
|
symbex Database -d ~/projects/datasette
|
41
41
|
```
|
42
|
+
If `symbex` encounters any Python code that it cannot parse, it will print a warning message and continue searching:
|
43
|
+
```
|
44
|
+
# Syntax error in path/badcode.py: expected ':' (<unknown>, line 1)
|
45
|
+
```
|
46
|
+
Pass `--silent` to suppress these warnings:
|
47
|
+
```bash
|
48
|
+
symbex MyClass --silent
|
49
|
+
```
|
42
50
|
|
43
51
|
## Example output
|
44
52
|
|
@@ -8,7 +8,12 @@ from .lib import code_for_node, find_symbol_nodes
|
|
8
8
|
@click.version_option()
|
9
9
|
@click.argument("symbols", nargs=-1)
|
10
10
|
@click.option(
|
11
|
-
"files",
|
11
|
+
"files",
|
12
|
+
"-f",
|
13
|
+
"--file",
|
14
|
+
type=click.Path(file_okay=True, dir_okay=False),
|
15
|
+
multiple=True,
|
16
|
+
help="Files to search",
|
12
17
|
)
|
13
18
|
@click.option(
|
14
19
|
"directories",
|
@@ -18,7 +23,12 @@ from .lib import code_for_node, find_symbol_nodes
|
|
18
23
|
multiple=True,
|
19
24
|
help="Directories to search",
|
20
25
|
)
|
21
|
-
|
26
|
+
@click.option(
|
27
|
+
"--silent",
|
28
|
+
is_flag=True,
|
29
|
+
help="Silently ignore Python files with parse errors",
|
30
|
+
)
|
31
|
+
def cli(symbols, files, directories, silent):
|
22
32
|
"""
|
23
33
|
Find symbols in Python code and print the code for them.
|
24
34
|
|
@@ -40,13 +50,18 @@ def cli(symbols, files, directories):
|
|
40
50
|
"""
|
41
51
|
if not files and not directories:
|
42
52
|
directories = ["."]
|
43
|
-
files =
|
53
|
+
files = [pathlib.Path(f) for f in files]
|
44
54
|
for directory in directories:
|
45
55
|
files.extend(pathlib.Path(directory).rglob("*.py"))
|
46
56
|
pwd = pathlib.Path(".").resolve()
|
47
57
|
for file in files:
|
48
58
|
code = file.read_text("utf-8") if hasattr(file, "read_text") else file.read()
|
49
|
-
|
59
|
+
try:
|
60
|
+
nodes = find_symbol_nodes(code, symbols)
|
61
|
+
except SyntaxError as ex:
|
62
|
+
if not silent:
|
63
|
+
click.secho(f"# Syntax error in {file}: {ex}", err=True, fg="yellow")
|
64
|
+
continue
|
50
65
|
for node in nodes:
|
51
66
|
# If file is within pwd, print relative path
|
52
67
|
# else print absolute path
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: symbex
|
3
|
-
Version: 0.2
|
3
|
+
Version: 0.2.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
|
@@ -54,6 +54,14 @@ To search within a specific directory and all of its subdirectories, use the `-d
|
|
54
54
|
```bash
|
55
55
|
symbex Database -d ~/projects/datasette
|
56
56
|
```
|
57
|
+
If `symbex` encounters any Python code that it cannot parse, it will print a warning message and continue searching:
|
58
|
+
```
|
59
|
+
# Syntax error in path/badcode.py: expected ':' (<unknown>, line 1)
|
60
|
+
```
|
61
|
+
Pass `--silent` to suppress these warnings:
|
62
|
+
```bash
|
63
|
+
symbex MyClass --silent
|
64
|
+
```
|
57
65
|
|
58
66
|
## Example output
|
59
67
|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import pathlib
|
2
|
+
import pytest
|
3
|
+
from click.testing import CliRunner
|
4
|
+
|
5
|
+
from symbex.cli import cli
|
6
|
+
|
7
|
+
|
8
|
+
@pytest.fixture
|
9
|
+
def directory_full_of_code(tmpdir):
|
10
|
+
for path, content in (
|
11
|
+
("foo.py", "def foo1():\n pass\n\n@decorated\ndef foo2():\n pass\n\n"),
|
12
|
+
("bar.py", "class BarClass:\n pass\n\n"),
|
13
|
+
("nested/baz.py", "def baz():\n pass\n\n"),
|
14
|
+
("nested/error.py", "def baz_error()" + "bug:\n pass\n\n"),
|
15
|
+
):
|
16
|
+
p = pathlib.Path(tmpdir / path)
|
17
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
18
|
+
p.write_text(content, "utf-8")
|
19
|
+
return tmpdir
|
20
|
+
|
21
|
+
|
22
|
+
@pytest.mark.parametrize(
|
23
|
+
"args,expected",
|
24
|
+
(
|
25
|
+
(["foo1", "--silent"], "# File: foo.py Line: 1\ndef foo1():\n pass\n\n"),
|
26
|
+
(
|
27
|
+
["foo*", "--silent"],
|
28
|
+
"# File: foo.py Line: 1\ndef foo1():\n pass\n\n# File: foo.py Line: 4\n@decorated\ndef foo2():\n pass\n\n",
|
29
|
+
),
|
30
|
+
(
|
31
|
+
["BarClass", "--silent"],
|
32
|
+
"# File: bar.py Line: 1\nclass BarClass:\n pass\n\n",
|
33
|
+
),
|
34
|
+
(
|
35
|
+
["baz", "--silent"],
|
36
|
+
"# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n",
|
37
|
+
),
|
38
|
+
# The -f option
|
39
|
+
(
|
40
|
+
["baz", "-f", "nested/baz.py", "--silent"],
|
41
|
+
"# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n",
|
42
|
+
),
|
43
|
+
# The -d option
|
44
|
+
(
|
45
|
+
["baz", "-d", "nested", "--silent"],
|
46
|
+
"# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n",
|
47
|
+
),
|
48
|
+
),
|
49
|
+
)
|
50
|
+
def test_fixture(directory_full_of_code, args, expected, monkeypatch):
|
51
|
+
runner = CliRunner()
|
52
|
+
monkeypatch.chdir(directory_full_of_code)
|
53
|
+
result = runner.invoke(cli, args, catch_exceptions=False)
|
54
|
+
assert result.exit_code == 0
|
55
|
+
assert result.stdout == expected
|
56
|
+
|
57
|
+
|
58
|
+
def test_errors(directory_full_of_code, monkeypatch):
|
59
|
+
# Test without --silent to see errors
|
60
|
+
runner = CliRunner(mix_stderr=False)
|
61
|
+
monkeypatch.chdir(directory_full_of_code)
|
62
|
+
result = runner.invoke(cli, ["baz"], catch_exceptions=False)
|
63
|
+
assert result.exit_code == 0
|
64
|
+
assert result.stdout == (
|
65
|
+
"# File: nested/baz.py Line: 1\n" "def baz():\n" " pass\n\n"
|
66
|
+
)
|
67
|
+
# This differs between different Python versions
|
68
|
+
assert result.stderr.startswith("# Syntax error in nested/error.py:")
|
symbex-0.2/tests/test_symbex.py
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
import pathlib
|
2
|
-
import pytest
|
3
|
-
from click.testing import CliRunner
|
4
|
-
|
5
|
-
from symbex.cli import cli
|
6
|
-
|
7
|
-
|
8
|
-
@pytest.fixture
|
9
|
-
def directory_full_of_code(tmpdir):
|
10
|
-
for path, content in (
|
11
|
-
("foo.py", "def foo1():\n pass\n\n@decorated\ndef foo2():\n pass\n\n"),
|
12
|
-
("bar.py", "class BarClass:\n pass\n\n"),
|
13
|
-
("nested/baz.py", "def baz():\n pass\n\n"),
|
14
|
-
):
|
15
|
-
p = pathlib.Path(tmpdir / path)
|
16
|
-
p.parent.mkdir(parents=True, exist_ok=True)
|
17
|
-
p.write_text(content, "utf-8")
|
18
|
-
return tmpdir
|
19
|
-
|
20
|
-
|
21
|
-
@pytest.mark.parametrize(
|
22
|
-
"args,expected",
|
23
|
-
(
|
24
|
-
(["foo1"], "# File: foo.py Line: 1\ndef foo1():\n pass\n\n"),
|
25
|
-
(
|
26
|
-
["foo*"],
|
27
|
-
"# File: foo.py Line: 1\ndef foo1():\n pass\n\n# File: foo.py Line: 4\n@decorated\ndef foo2():\n pass\n\n",
|
28
|
-
),
|
29
|
-
(["BarClass"], "# File: bar.py Line: 1\nclass BarClass:\n pass\n\n"),
|
30
|
-
(["baz"], "# File: nested/baz.py Line: 1\ndef baz():\n pass\n\n"),
|
31
|
-
),
|
32
|
-
)
|
33
|
-
def test_fixture(directory_full_of_code, args, expected, monkeypatch):
|
34
|
-
runner = CliRunner()
|
35
|
-
monkeypatch.chdir(directory_full_of_code)
|
36
|
-
result = runner.invoke(cli, args, catch_exceptions=False)
|
37
|
-
assert result.exit_code == 0
|
38
|
-
assert result.stdout == expected
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|