Skip to content

Commit ffe2214

Browse files
committed
STY: check for private imports/lookups
1 parent 25f3b97 commit ffe2214

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,9 @@ check:
3232
--included-file-extensions="py" \
3333
--excluded-file-paths=pandas/tests,asv_bench/,pandas/_vendored \
3434
pandas/
35+
36+
python3 scripts/validate_unwanted_patterns.py \
37+
--validation-type="private_import_across_module" \
38+
--included-file-extensions="py" \
39+
--excluded-file-paths=pandas/tests/,asv_bench/
40+
pandas/

ci/code_checks.sh

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,18 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then
116116
fi
117117
RET=$(($RET + $?)) ; echo $MSG "DONE"
118118

119-
MSG='Check for use of private module attribute access' ; echo $MSG
119+
MSG='Check for import of private attributes across modules' ; echo $MSG
120120
if [[ "$GITHUB_ACTIONS" == "true" ]]; then
121-
$BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --included-file-extensions="py" --excluded-file-paths=pandas/tests,asv_bench/,pandas/_vendored --format="##[error]{source_path}:{line_number}:{msg}" pandas/
121+
$BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" --included-file-extensions="py" --excluded-file-paths=pandas/tests,asv_bench/,pandas/_vendored --format="##[error]{source_path}:{line_number}:{msg}" pandas/
122122
else
123-
$BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --included-file-extensions="py" --excluded-file-paths=pandas/tests,asv_bench/,pandas/_vendored pandas/
123+
$BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" --included-file-extensions="py" --excluded-file-paths=pandas/tests,asv_bench/,pandas/_vendored pandas/
124+
RET=$(($RET + $?)) ; echo $MSG "DONE"
125+
126+
MSG='Check for use of private functions across modules' ; echo $MSG
127+
if [[ "$GITHUB_ACTIONS" == "true" ]]; then
128+
$BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --included-file-extensions="py" --format="##[error]{source_path}:{line_number}:{msg}" pandas/
129+
else
130+
$BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --included-file-extensions="py" pandas/
124131
fi
125132
RET=$(($RET + $?)) ; echo $MSG "DONE"
126133

scripts/validate_unwanted_patterns.py

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,25 @@
1818
import tokenize
1919
from typing import IO, Callable, FrozenSet, Iterable, List, Set, Tuple
2020

21+
PRIVATE_IMPORTS_TO_IGNORE: Set[str] = {
22+
"_extension_array_shared_docs",
23+
"_index_shared_docs",
24+
"_merge_doc",
25+
"_shared_docs",
26+
"_new_Index",
27+
"_new_PeriodIndex",
28+
"_doc_template",
29+
"_interval_shared_docs",
30+
"_apply_docs",
31+
"_arith_doc_FRAME",
32+
"_flex_comp_doc_FRAME",
33+
"_make_flex_doc",
34+
"_op_descriptions",
35+
"_pipe_template",
36+
"_testing",
37+
"_test_decorators",
38+
}
39+
2140

2241
def _get_literal_string_prefix_len(token_string: str) -> int:
2342
"""
@@ -164,6 +183,36 @@ def private_function_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str
164183
yield (node.lineno, f"Private function '{module_name}.{function_name}'")
165184

166185

186+
def private_import_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str]]:
187+
"""
188+
Checking that a private function is not imported across modules.
189+
Parameters
190+
----------
191+
file_obj : IO
192+
File-like object containing the Python code to validate.
193+
Yields
194+
------
195+
line_number : int
196+
Line number of import statement, that imports the private function.
197+
msg : str
198+
Explenation of the error.
199+
"""
200+
contents = file_obj.read()
201+
tree = ast.parse(contents)
202+
203+
for node in ast.walk(tree):
204+
if not (isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom)):
205+
continue
206+
207+
for module in node.names:
208+
module_name = module.name.split(".")[-1]
209+
if module_name in PRIVATE_IMPORTS_TO_IGNORE:
210+
continue
211+
212+
if module_name.startswith("_"):
213+
yield (node.lineno, f"Import of internal function {repr(module_name)}")
214+
215+
167216
def strings_to_concatenate(file_obj: IO[str]) -> Iterable[Tuple[int, str]]:
168217
"""
169218
This test case is necessary after 'Black' (https://github.com/psf/black),
@@ -419,6 +468,7 @@ def main(
419468
available_validation_types: List[str] = [
420469
"bare_pytest_raises",
421470
"private_function_across_module",
471+
"private_import_across_module",
422472
"strings_to_concatenate",
423473
"strings_with_wrong_placed_whitespace",
424474
]
@@ -444,12 +494,12 @@ def main(
444494
parser.add_argument(
445495
"--included-file-extensions",
446496
default="py,pyx,pxd,pxi",
447-
help="Coma seperated file extensions to check.",
497+
help="Comma seperated file extensions to check.",
448498
)
449499
parser.add_argument(
450500
"--excluded-file-paths",
451501
default="asv_bench/env",
452-
help="Comma separated file extensions to check.",
502+
help="Comma separated file paths to exclude.",
453503
)
454504

455505
args = parser.parse_args()

0 commit comments

Comments
 (0)