Skip to content

Commit 18a1d77

Browse files
committed
Ignore unresolved requirements
1 parent 8f7e380 commit 18a1d77

10 files changed

+32
-267
lines changed

Diff for: src/ssort/__init__.py

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
"""
22
The python source code statement sorter.
33
"""
4-
from ssort._exceptions import (
5-
DecodingError,
6-
ParseError,
7-
ResolutionError,
8-
UnknownEncodingError,
9-
WildcardImportError,
10-
)
4+
from ssort._exceptions import DecodingError, ParseError, UnknownEncodingError
115
from ssort._ssort import ssort
126

137
# Let linting tools know that we do mean to re-export exception classes.
148
assert DecodingError is not None
159
assert ParseError is not None
16-
assert ResolutionError is not None
1710
assert UnknownEncodingError is not None
18-
assert WildcardImportError is not None
1911

2012
try:
2113
from ssort._version import VERSION as __version__ # type: ignore

Diff for: src/ssort/_dependencies.py

+2-47
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from ssort._graphs import Graph
33

44

5-
def module_statements_graph(statements, *, on_unresolved, on_wildcard_import):
5+
def module_statements_graph(statements):
66
"""
77
Constructs a graph of the interdependencies in a list of module level
88
statements.
@@ -11,16 +11,6 @@ def module_statements_graph(statements, *, on_unresolved, on_wildcard_import):
1111
An ordered list of opaque `Statement` objects from which to construct
1212
the graph.
1313
14-
:param on_unresolved:
15-
An callback that should be invoked for each unresolved dependency. Can
16-
safely raise any arbitrary exception to abort constructing the graph.
17-
If no exception is raised, the graph returned by this function will not
18-
contain a link for the missing requirement.
19-
:param on_wildcard_import:
20-
A callback that should be invoked if ssort detects a `*` import. If no
21-
exception is raised, all dangling references will be pointed back to the
22-
last `*` import.
23-
2414
:returns:
2515
A `Graph` mapping from statements to the set of statements that they
2616
depend on.
@@ -35,7 +25,6 @@ def module_statements_graph(statements, *, on_unresolved, on_wildcard_import):
3525
for requirement in statement.requirements():
3626
all_requirements.append(requirement)
3727

38-
# TODO error if requirement is not deferred.
3928
if requirement.name in scope:
4029
resolved[requirement] = scope[requirement.name]
4130
continue
@@ -45,12 +34,6 @@ def module_statements_graph(statements, *, on_unresolved, on_wildcard_import):
4534
continue
4635

4736
for name in statement.bindings():
48-
if name == "*":
49-
on_wildcard_import(
50-
lineno=statement.node.lineno,
51-
col_offset=statement.node.col_offset,
52-
)
53-
5437
scope[name] = statement
5538

5639
# Patch up dependencies that couldn't be resolved immediately.
@@ -63,41 +46,13 @@ def module_statements_graph(statements, *, on_unresolved, on_wildcard_import):
6346

6447
resolved[requirement] = scope[requirement.name]
6548

66-
if "*" in scope:
67-
for requirement in all_requirements:
68-
if requirement in resolved:
69-
continue
70-
71-
resolved[requirement] = scope["*"]
72-
73-
else:
74-
unresolved = [
75-
requirement
76-
for requirement in all_requirements
77-
if requirement not in resolved
78-
]
79-
80-
for requirement in unresolved:
81-
on_unresolved(
82-
f"could not resolve {requirement.name!r}",
83-
name=requirement.name,
84-
lineno=requirement.lineno,
85-
col_offset=requirement.col_offset,
86-
)
87-
88-
if unresolved:
89-
# Not safe to attempt to re-order in the event of unresolved
90-
# dependencies. A typo could cause a statement to be moved ahead of
91-
# something that it should depend on.
92-
return None
93-
9449
graph = Graph()
9550
for statement in statements:
9651
graph.add_node(statement)
9752

9853
for statement in statements:
9954
for requirement in statement.requirements():
100-
if resolved[requirement] is not None:
55+
if resolved.get(requirement) is not None:
10156
graph.add_dependency(statement, resolved[requirement])
10257

10358
# Add links between statements that overwrite the same binding to make sure

Diff for: src/ssort/_exceptions.py

-15
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,3 @@ def __init__(self, msg, *, lineno, col_offset):
1313
super().__init__(msg)
1414
self.lineno = lineno
1515
self.col_offset = col_offset
16-
17-
18-
class ResolutionError(Exception):
19-
def __init__(self, msg, *, name, lineno, col_offset):
20-
super().__init__(msg)
21-
self.name = name
22-
self.lineno = lineno
23-
self.col_offset = col_offset
24-
25-
26-
class WildcardImportError(Exception):
27-
def __init__(self, msg, *, lineno, col_offset):
28-
super().__init__(msg)
29-
self.lineno = lineno
30-
self.col_offset = col_offset

Diff for: src/ssort/_main.py

-17
Original file line numberDiff line numberDiff line change
@@ -104,28 +104,11 @@ def _on_parse_error(message, *, lineno, col_offset, **kwargs):
104104
+ f"line {lineno}, column {col_offset}\n"
105105
)
106106

107-
def _on_unresolved(message, *, name, lineno, col_offset, **kwargs):
108-
nonlocal errors
109-
errors = True
110-
111-
sys.stderr.write(
112-
f"ERROR: unresolved dependency {name!r} "
113-
+ f"in {escape_path(path)}: "
114-
+ f"line {lineno}, column {col_offset}\n"
115-
)
116-
117-
def _on_wildcard_import(**kwargs):
118-
sys.stderr.write(
119-
"WARNING: can't determine dependencies on * import\n"
120-
)
121-
122107
try:
123108
updated = ssort(
124109
original,
125110
filename=escape_path(path),
126111
on_parse_error=_on_parse_error,
127-
on_unresolved=_on_unresolved,
128-
on_wildcard_import=_on_wildcard_import,
129112
)
130113

131114
if errors:

Diff for: src/ssort/_ssort.py

+2-65
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,7 @@
77
class_statements_runtime_graph,
88
module_statements_graph,
99
)
10-
from ssort._exceptions import (
11-
DecodingError,
12-
ParseError,
13-
ResolutionError,
14-
UnknownEncodingError,
15-
WildcardImportError,
16-
)
10+
from ssort._exceptions import DecodingError, ParseError, UnknownEncodingError
1711
from ssort._graphs import (
1812
is_topologically_sorted,
1913
replace_cycles,
@@ -388,70 +382,19 @@ def _interpret_on_parse_error_action(on_parse_error):
388382
return on_parse_error
389383

390384

391-
def _on_unresolved_ignore(message, *, name, lineno, col_offset, **kwargs):
392-
pass
393-
394-
395-
def _on_unresolved_raise(message, *, name, lineno, col_offset, **kwargs):
396-
raise ResolutionError(
397-
message,
398-
name=name,
399-
lineno=lineno,
400-
col_offset=col_offset,
401-
)
402-
403-
404-
def _interpret_on_unresolved_action(on_unresolved):
405-
if on_unresolved == "ignore":
406-
return _on_unresolved_ignore
407-
408-
if on_unresolved == "raise":
409-
return _on_unresolved_raise
410-
411-
return on_unresolved
412-
413-
414-
def _on_wildcard_import_ignore(**kwargs):
415-
pass
416-
417-
418-
def _on_wildcard_import_raise(*, lineno, col_offset, **kwargs):
419-
raise WildcardImportError(
420-
"can't reliably determine dependencies on * import",
421-
lineno=lineno,
422-
col_offset=col_offset,
423-
)
424-
425-
426-
def _interpret_on_wildcard_import_action(on_wildcard_import):
427-
if on_wildcard_import == "ignore":
428-
return _on_wildcard_import_ignore
429-
430-
if on_wildcard_import == "raise":
431-
return _on_wildcard_import_raise
432-
433-
return on_wildcard_import
434-
435-
436385
def ssort(
437386
text,
438387
*,
439388
filename="<unknown>",
440389
on_unknown_encoding_error="raise",
441390
on_decoding_error="raise",
442391
on_parse_error="raise",
443-
on_unresolved="raise",
444-
on_wildcard_import="raise",
445392
):
446393
on_unknown_encoding_error = _interpret_on_unknown_encoding_action(
447394
on_unknown_encoding_error
448395
)
449396
on_decoding_error = _interpret_on_decoding_error_action(on_decoding_error)
450397
on_parse_error = _interpret_on_parse_error_action(on_parse_error)
451-
on_unresolved = _interpret_on_unresolved_action(on_unresolved)
452-
on_wildcard_import = _interpret_on_wildcard_import_action(
453-
on_wildcard_import
454-
)
455398

456399
try:
457400
encoding = None
@@ -478,13 +421,7 @@ def ssort(
478421
if not statements:
479422
return text
480423

481-
graph = module_statements_graph(
482-
statements,
483-
on_unresolved=on_unresolved,
484-
on_wildcard_import=on_wildcard_import,
485-
)
486-
if graph is None:
487-
return text
424+
graph = module_statements_graph(statements)
488425

489426
replace_cycles(graph, key=sort_key_from_iter(statements))
490427

Diff for: tests/test_dependencies.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ def _clean(source):
88
return textwrap.dedent(source).strip() + "\n"
99

1010

11-
def _unreachable(*args, **kwargs):
12-
raise AssertionError("unreachable")
13-
14-
1511
def test_dependencies_ordered_by_first_use():
1612
source = _clean(
1713
"""
@@ -28,8 +24,6 @@ def b():
2824
"""
2925
)
3026
c, a, b = statements = list(parse(source, filename="<unknown>"))
31-
graph = module_statements_graph(
32-
statements, on_unresolved=_unreachable, on_wildcard_import=_unreachable
33-
)
27+
graph = module_statements_graph(statements)
3428

3529
assert list(graph.dependencies[a]) == [b, c]

Diff for: tests/test_error_hooks.py

+1-85
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import pytest
22

3-
from ssort import (
4-
DecodingError,
5-
ParseError,
6-
ResolutionError,
7-
UnknownEncodingError,
8-
WildcardImportError,
9-
ssort,
10-
)
3+
from ssort import DecodingError, ParseError, UnknownEncodingError, ssort
114

125

136
class _DummyException(Exception):
@@ -104,80 +97,3 @@ def on_parse_error(message, *, lineno, col_offset):
10497
with pytest.raises(_DummyException) as exc_info:
10598
ssort(original, on_parse_error=on_parse_error)
10699
assert exc_info.value.args == ("invalid syntax", 1, 4)
107-
108-
109-
# === Unresolved ===============================================================
110-
111-
112-
def test_on_unresolved_raise():
113-
original = "def fun():\n unresolved()"
114-
115-
with pytest.raises(ResolutionError) as exc_info:
116-
ssort(original, on_unresolved="raise")
117-
118-
assert str(exc_info.value) == "could not resolve 'unresolved'"
119-
assert exc_info.value.name == "unresolved"
120-
assert exc_info.value.lineno == 2
121-
assert exc_info.value.col_offset == 4
122-
123-
124-
def test_on_unresolved_ignore():
125-
original = "def fun():\n unresolved()"
126-
127-
actual = ssort(original, on_unresolved="ignore")
128-
129-
assert actual == original
130-
131-
132-
def test_on_unresolved_callback():
133-
original = "def fun():\n unresolved()"
134-
135-
def on_unresolved(message, *, name, lineno, col_offset):
136-
raise _DummyException(message, name, lineno, col_offset)
137-
138-
with pytest.raises(_DummyException) as exc_info:
139-
ssort(original, on_unresolved=on_unresolved)
140-
141-
assert exc_info.value.args == (
142-
"could not resolve 'unresolved'",
143-
"unresolved",
144-
2,
145-
4,
146-
)
147-
148-
149-
# === Wildcard Import ==========================================================
150-
151-
152-
def test_on_wildcard_import_raise():
153-
original = "from module import *"
154-
155-
with pytest.raises(WildcardImportError) as exc_info:
156-
ssort(original, on_wildcard_import="raise")
157-
158-
assert (
159-
str(exc_info.value)
160-
== "can't reliably determine dependencies on * import"
161-
)
162-
assert exc_info.value.lineno == 1
163-
assert exc_info.value.col_offset == 0
164-
165-
166-
def test_on_wildcard_import_ignore():
167-
original = "from module import *\n"
168-
169-
actual = ssort(original, on_wildcard_import="ignore")
170-
171-
assert actual == original
172-
173-
174-
def test_on_wildcard_import_callback():
175-
original = "from module import *"
176-
177-
def on_wildcard_import(*, lineno, col_offset):
178-
raise _DummyException(lineno, col_offset)
179-
180-
with pytest.raises(_DummyException) as exc_info:
181-
ssort(original, on_wildcard_import=on_wildcard_import)
182-
183-
assert exc_info.value.args == (1, 0)

0 commit comments

Comments
 (0)