-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve catch-all handling and avoid some pylint suppressions #1919
Changes from all commits
2f7ec58
e0796d6
9a7c1bd
fe7de63
f24ab05
5433d90
13258d5
5327656
330bcc6
8509813
a6a13c2
a862663
24851a2
da7133a
5fce3ba
2a169e1
df1878c
4f31198
ef94c88
a42b314
274a2a9
ef3ac4f
33de8a1
d023f05
63f6e49
3473b9f
6006d56
193a4d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,10 +10,15 @@ | |
from databricks.labs.ucx.source_code.linters.files import FileLoader, ImportFileResolver | ||
from databricks.labs.ucx.source_code.linters.python_ast import Tree | ||
from databricks.labs.ucx.source_code.notebooks.cells import CellLanguage, PipCell, PipMagic, MagicCommand | ||
from databricks.labs.ucx.source_code.notebooks.cells import ( | ||
GraphBuilder, | ||
PythonCell, | ||
) | ||
from databricks.labs.ucx.source_code.notebooks.loaders import ( | ||
NotebookResolver, | ||
NotebookLoader, | ||
) | ||
from databricks.labs.ucx.source_code.path_lookup import PathLookup | ||
from databricks.labs.ucx.source_code.python_libraries import PythonLibraryResolver | ||
from databricks.labs.ucx.source_code.known import KnownList | ||
|
||
|
@@ -167,6 +172,58 @@ def test_pip_cell_build_dependency_graph_handles_multiline_code(): | |
graph.register_library.assert_called_once_with("databricks") | ||
|
||
|
||
def test_graph_builder_parse_error( | ||
simple_dependency_resolver: DependencyResolver, mock_path_lookup: PathLookup | ||
) -> None: | ||
"""Check that internal parsing errors are caught and logged.""" | ||
# Fixture. | ||
dependency = Dependency(FileLoader(), Path("")) | ||
graph = DependencyGraph(dependency, None, simple_dependency_resolver, mock_path_lookup, CurrentSessionState()) | ||
graph.new_graph_builder_context() | ||
builder = GraphBuilder(graph.new_graph_builder_context()) | ||
|
||
# Run the test. | ||
problems = builder.build_graph_from_python_source("this is not valid python") | ||
|
||
# Check results. | ||
assert [ | ||
problem | ||
for problem in problems | ||
if problem.code == "parse-error" and problem.message.startswith("Could not parse Python code") | ||
] | ||
|
||
|
||
def test_parses_python_cell_with_magic_commands(simple_dependency_resolver, mock_path_lookup): | ||
code = """ | ||
a = 'something' | ||
%pip install databricks | ||
b = 'else' | ||
""" | ||
cell = PythonCell(code, original_offset=1) | ||
dependency = Dependency(FileLoader(), Path("")) | ||
graph = DependencyGraph(dependency, None, simple_dependency_resolver, mock_path_lookup, CurrentSessionState()) | ||
problems = cell.build_dependency_graph(graph) | ||
assert not problems | ||
|
||
|
||
@pytest.mark.xfail(reason="Line-magic as an expression is not supported ", strict=True) | ||
def test_python_cell_with_expression_magic( | ||
simple_dependency_resolver: DependencyResolver, mock_path_lookup: PathLookup | ||
) -> None: | ||
"""Line magic (%) can be used in places where expressions are expected; check that this is handled.""" | ||
# Fixture | ||
code = "current_directory = %pwd" | ||
cell = PythonCell(code, original_offset=1) | ||
dependency = Dependency(FileLoader(), Path("")) | ||
graph = DependencyGraph(dependency, None, simple_dependency_resolver, mock_path_lookup, CurrentSessionState()) | ||
|
||
# Run the test | ||
problems = cell.build_dependency_graph(graph) | ||
|
||
# Verify there were no problems. | ||
assert not problems | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"code,split", | ||
[ | ||
|
@@ -193,6 +250,12 @@ def test_pip_cell_build_dependency_graph_handles_multiline_code(): | |
], | ||
) | ||
def test_pip_magic_split(code, split): | ||
# Avoid direct protected access to the _split method. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oke, that is an interesting workaround. I am not settled on the protected access in test cases, I like them sometimes, when it is clear unit testable functionality, like here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When code has been well-designed with testing in mind and makes good use of functional composition, I agree it can often be avoided. However in practice most codebases don't function that way and the fixtures for unit tests are (by necessity) tightly coupled to the implementation of whatever is being tested. This means better-than-public access is frequently required. My preferred approach here would be to relax the linting rules so that unit tests are allowed to access protected attributes. The current situation is that:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with allowing the protected access in the tests. I ran into the same problem. Though, I think it good practice to nudge the test to test the public API's in the first place, but also have the option to narrowly test non public API's |
||
class _PipMagicFriend(PipMagic): | ||
@classmethod | ||
def split(cls, code: str) -> list[str]: | ||
return cls._split(code) | ||
|
||
assert PipMagic._split(code) == split # pylint: disable=protected-access | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this one more narrow?