|
18 | 18 | import tokenize
|
19 | 19 | from typing import IO, Callable, FrozenSet, Iterable, List, Set, Tuple
|
20 | 20 |
|
| 21 | +PRIVATE_IMPORTS_TO_IGNORE: Set[str] = { |
| 22 | + "_extension_array_shared_docs", |
| 23 | + "_index_shared_docs", |
| 24 | + "_interval_shared_docs", |
| 25 | + "_merge_doc", |
| 26 | + "_shared_docs", |
| 27 | + "_apply_docs", |
| 28 | + "_new_Index", |
| 29 | + "_new_PeriodIndex", |
| 30 | + "_doc_template", |
| 31 | + "_agg_template", |
| 32 | + "_pipe_template", |
| 33 | + "_get_version", |
| 34 | + "__main__", |
| 35 | + "_transform_template", |
| 36 | + "_arith_doc_FRAME", |
| 37 | + "_flex_comp_doc_FRAME", |
| 38 | + "_make_flex_doc", |
| 39 | + "_op_descriptions", |
| 40 | + "_IntegerDtype", |
| 41 | + "_use_inf_as_na", |
| 42 | + "_get_plot_backend", |
| 43 | + "_matplotlib", |
| 44 | + "_arrow_utils", |
| 45 | + "_registry", |
| 46 | + "_get_offset", # TODO: remove after get_offset deprecation enforced |
| 47 | + "_test_parse_iso8601", |
| 48 | + "_json_normalize", # TODO: remove after deprecation is enforced |
| 49 | + "_testing", |
| 50 | + "_test_decorators", |
| 51 | + "__version__", # check np.__version__ in compat.numpy.function |
| 52 | +} |
| 53 | + |
21 | 54 |
|
22 | 55 | def _get_literal_string_prefix_len(token_string: str) -> int:
|
23 | 56 | """
|
@@ -164,6 +197,36 @@ def private_function_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str
|
164 | 197 | yield (node.lineno, f"Private function '{module_name}.{function_name}'")
|
165 | 198 |
|
166 | 199 |
|
| 200 | +def private_import_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: |
| 201 | + """ |
| 202 | + Checking that a private function is not imported across modules. |
| 203 | + Parameters |
| 204 | + ---------- |
| 205 | + file_obj : IO |
| 206 | + File-like object containing the Python code to validate. |
| 207 | + Yields |
| 208 | + ------ |
| 209 | + line_number : int |
| 210 | + Line number of import statement, that imports the private function. |
| 211 | + msg : str |
| 212 | + Explenation of the error. |
| 213 | + """ |
| 214 | + contents = file_obj.read() |
| 215 | + tree = ast.parse(contents) |
| 216 | + |
| 217 | + for node in ast.walk(tree): |
| 218 | + if not (isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom)): |
| 219 | + continue |
| 220 | + |
| 221 | + for module in node.names: |
| 222 | + module_name = module.name.split(".")[-1] |
| 223 | + if module_name in PRIVATE_IMPORTS_TO_IGNORE: |
| 224 | + continue |
| 225 | + |
| 226 | + if module_name.startswith("_"): |
| 227 | + yield (node.lineno, f"Import of internal function {repr(module_name)}") |
| 228 | + |
| 229 | + |
167 | 230 | def strings_to_concatenate(file_obj: IO[str]) -> Iterable[Tuple[int, str]]:
|
168 | 231 | """
|
169 | 232 | This test case is necessary after 'Black' (https://github.com/psf/black),
|
@@ -419,6 +482,7 @@ def main(
|
419 | 482 | available_validation_types: List[str] = [
|
420 | 483 | "bare_pytest_raises",
|
421 | 484 | "private_function_across_module",
|
| 485 | + "private_import_across_module", |
422 | 486 | "strings_to_concatenate",
|
423 | 487 | "strings_with_wrong_placed_whitespace",
|
424 | 488 | ]
|
@@ -449,7 +513,7 @@ def main(
|
449 | 513 | parser.add_argument(
|
450 | 514 | "--excluded-file-paths",
|
451 | 515 | default="asv_bench/env",
|
452 |
| - help="Comma separated file extensions to check.", |
| 516 | + help="Comma separated file paths to exclude.", |
453 | 517 | )
|
454 | 518 |
|
455 | 519 | args = parser.parse_args()
|
|
0 commit comments