From dd7f1d0362a4fede8049bf135fe4bcdbb57b49bc Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 8 Apr 2020 16:06:10 +0300 Subject: [PATCH 1/3] CI: Check private function not used across modules --- ci/code_checks.sh | 13 +++++++ scripts/validate_unwanted_patterns.py | 52 ++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 8901efad56f79..8e47b1ffb5b76 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -116,6 +116,19 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then fi RET=$(($RET + $?)) ; echo $MSG "DONE" + MSG='Check for use of private functions across modules' ; echo $MSG + if [[ "$GITHUB_ACTIONS" == "true" ]]; then + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --format="##[error]{source_path}:{line_number}:{msg}" pandas/core/ + RET=$(($RET + $?)) ; echo $MSG "DONE" + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --format="##[error]{source_path}:{line_number}:{msg}" pandas/tseries/ + RET=$(($RET + $?)) ; echo $MSG "DONE" + else + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/core/ + RET=$(($RET + $?)) ; echo $MSG "DONE" + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/tseries/ + RET=$(($RET + $?)) ; echo $MSG "DONE" + fi + echo "isort --version-number" isort --version-number diff --git a/scripts/validate_unwanted_patterns.py b/scripts/validate_unwanted_patterns.py index b476ab5a818c5..ee980cf0fb0fe 100755 --- a/scripts/validate_unwanted_patterns.py +++ b/scripts/validate_unwanted_patterns.py @@ -16,7 +16,7 @@ import sys import token import tokenize -from typing import IO, Callable, Iterable, List, Tuple +from typing import IO, Callable, Iterable, List, Set, Tuple FILE_EXTENSIONS_TO_CHECK: Tuple[str, ...] = (".py", ".pyx", ".pxi.ini", ".pxd") PATHS_TO_IGNORE: Tuple[str, ...] = ("asv_bench/env",) @@ -115,6 +115,55 @@ def bare_pytest_raises(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: ) +def private_function_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: + """ + Checking that a private function is not used across modules. + + Parameters + ---------- + file_obj : IO + File-like object containing the Python code to validate. + + Yields + ------ + line_number : int + Line number of the private function that is used across modules. + msg : str + Explenation of the error. + """ + contents = file_obj.read() + tree = ast.parse(contents) + + imported_modules: Set[str] = set() + + for node in ast.walk(tree): + if isinstance(node, (ast.Import, ast.ImportFrom)): + for module in node.names: + module_fqdn = module.name if module.asname is None else module.asname + imported_modules.add(module_fqdn) + + if not isinstance(node, ast.Call): + continue + + try: + module_name = node.func.value.id + function_name = node.func.attr + except AttributeError: + continue + + # Exception section # + + # (Debatable) Class case + if module_name[0].isupper(): + continue + # (Debatable) Dunder methods case + elif function_name.startswith("__") and function_name.endswith("__"): + continue + + if module_name in imported_modules and function_name.startswith("_"): + yield (node.lineno, f"Private function '{module_name}.{function_name}'") + + def strings_to_concatenate(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: """ This test case is necessary after 'Black' (https://github.com/psf/black), @@ -358,6 +407,7 @@ def main( if __name__ == "__main__": available_validation_types: List[str] = [ "bare_pytest_raises", + "private_function_across_module", "strings_to_concatenate", "strings_with_wrong_placed_whitespace", ] From 7e11430cf24e105a6b3616c2108ece617b7ec5dd Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Sat, 11 Apr 2020 16:03:31 +0300 Subject: [PATCH 2/3] Revert some changes made due merge conflict --- scripts/validate_unwanted_patterns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/validate_unwanted_patterns.py b/scripts/validate_unwanted_patterns.py index dfabf7b1f08e3..1fd50f09c9eca 100755 --- a/scripts/validate_unwanted_patterns.py +++ b/scripts/validate_unwanted_patterns.py @@ -16,7 +16,7 @@ import sys import token import tokenize -from typing import IO, Callable, FrozenSet, Iterable, List, Tuple +from typing import IO, Callable, FrozenSet, Iterable, List, Set, Tuple PATHS_TO_IGNORE: Tuple[str, ...] = ("asv_bench/env",) From 232f16850976abcc1aa78c432bd9d619a5d5db83 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Sat, 11 Apr 2020 16:12:19 +0300 Subject: [PATCH 3/3] Checking the whole pandas directory --- ci/code_checks.sh | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index c8f6ca34f05cf..ff6d23c62fc28 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -118,16 +118,11 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then MSG='Check for use of private functions across modules' ; echo $MSG if [[ "$GITHUB_ACTIONS" == "true" ]]; then - $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --format="##[error]{source_path}:{line_number}:{msg}" pandas/core/ - RET=$(($RET + $?)) ; echo $MSG "DONE" - $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --format="##[error]{source_path}:{line_number}:{msg}" pandas/tseries/ - RET=$(($RET + $?)) ; echo $MSG "DONE" + $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/ else - $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/core/ - RET=$(($RET + $?)) ; echo $MSG "DONE" - $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/tseries/ - RET=$(($RET + $?)) ; echo $MSG "DONE" + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" --included-file-extensions="py" pandas/ fi + RET=$(($RET + $?)) ; echo $MSG "DONE" echo "isort --version-number" isort --version-number