From d9f3928ec9b8a10912661de8947111e19f5940b6 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Mon, 23 Mar 2020 20:26:55 +0200 Subject: [PATCH 1/7] CI: Check that private functions are not used across modules --- ci/code_checks.sh | 8 ++++++++ scripts/validate_unwanted_patterns.py | 29 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 15b4128424eb1..0868c7b6a3a12 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -232,6 +232,14 @@ if [[ -z "$CHECK" || "$CHECK" == "patterns" ]]; then invgrep -R --include=*.{py,pyx} 'xrange' pandas 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/ + else + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/core + fi + RET=$(($RET + $?)) ; echo $MSG "DONE" + MSG='Check that no file in the repo contains trailing whitespaces' ; echo $MSG INVGREP_APPEND=" <- trailing whitespaces found" invgrep -RI --exclude=\*.{svg,c,cpp,html,js} --exclude-dir=env "\s$" * diff --git a/scripts/validate_unwanted_patterns.py b/scripts/validate_unwanted_patterns.py index c4be85ffe7306..f4ea1490081f6 100755 --- a/scripts/validate_unwanted_patterns.py +++ b/scripts/validate_unwanted_patterns.py @@ -11,6 +11,7 @@ """ import argparse +import ast import os import sys import token @@ -102,6 +103,33 @@ def bare_pytest_raises(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: break +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 import statement, that imports the private function. + msg : str + Explenation of the error. + """ + contents = file_obj.read() + tree = ast.parse(contents) + + for node in ast.walk(tree): + if not (isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom)): + continue + + if any(mod.name.split(".")[-1].startswith("_") for mod in node.names): + yield (node.lineno, "Use of private function across modules found.") + + def strings_to_concatenate(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: """ This test case is necessary after 'Black' (https://github.com/psf/black), @@ -343,6 +371,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 4786cf7f6ab3d61dddd2021d25365ca2e85139d2 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 1 Apr 2020 20:31:59 +0300 Subject: [PATCH 2/7] Add option to ignore specific imports --- scripts/validate_unwanted_patterns.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/validate_unwanted_patterns.py b/scripts/validate_unwanted_patterns.py index e6fe3972c4987..e8088828dac20 100755 --- a/scripts/validate_unwanted_patterns.py +++ b/scripts/validate_unwanted_patterns.py @@ -16,11 +16,18 @@ 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",) +PRIVATE_IMPORTS_TO_IGNORE: Set[str] = { + "_extension_array_shared_docs", + "_index_shared_docs", + "_merge_doc", + "_shared_docs", +} + def _get_literal_string_prefix_len(token_string: str) -> int: """ @@ -138,8 +145,13 @@ def private_function_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str if not (isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom)): continue - if any(mod.name.split(".")[-1].startswith("_") for mod in node.names): - yield (node.lineno, "Use of private function across modules found.") + for module in node.names: + module_name = module.name.split(".")[-1] + if module_name in PRIVATE_IMPORTS_TO_IGNORE: + continue + + if module_name.startswith("_"): + yield (node.lineno, f"Import of internal function {repr(module_name)}") def strings_to_concatenate(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: From 19774fa75e56a9fa24558994863060135e2908b5 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 8 Apr 2020 13:29:03 +0300 Subject: [PATCH 3/7] Moving CI check to the correct place --- ci/code_checks.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 2aa53cd7f4ddf..c451a794db6da 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -116,6 +116,14 @@ 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/ + else + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/core + fi + RET=$(($RET + $?)) ; echo $MSG "DONE" + echo "isort --version-number" isort --version-number @@ -232,14 +240,6 @@ if [[ -z "$CHECK" || "$CHECK" == "patterns" ]]; then invgrep -R --include=*.{py,pyx} 'xrange' pandas 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/ - else - $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/core - fi - RET=$(($RET + $?)) ; echo $MSG "DONE" - MSG='Check that no file in the repo contains trailing whitespaces' ; echo $MSG INVGREP_APPEND=" <- trailing whitespaces found" invgrep -RI --exclude=\*.{svg,c,cpp,html,js} --exclude-dir=env "\s$" * From 8fa6adfb0697d87d1050f63c5635d090023d4897 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 8 Apr 2020 13:38:49 +0300 Subject: [PATCH 4/7] Renamed function --- ci/code_checks.sh | 6 +++--- scripts/validate_unwanted_patterns.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 14991a90fb9d9..ddb3719786445 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -116,11 +116,11 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then fi RET=$(($RET + $?)) ; echo $MSG "DONE" - MSG='Check for use of private functions across modules' ; echo $MSG + MSG='Check for use of private import 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/ + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" --format="##[error]{source_path}:{line_number}:{msg}" pandas/core/ else - $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_function_across_module" pandas/core + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" pandas/core fi RET=$(($RET + $?)) ; echo $MSG "DONE" diff --git a/scripts/validate_unwanted_patterns.py b/scripts/validate_unwanted_patterns.py index e8088828dac20..ea9875d702a8a 100755 --- a/scripts/validate_unwanted_patterns.py +++ b/scripts/validate_unwanted_patterns.py @@ -122,7 +122,7 @@ 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]]: +def private_import_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: """ Checking that a private function is not used across modules. @@ -397,7 +397,7 @@ def main( if __name__ == "__main__": available_validation_types: List[str] = [ "bare_pytest_raises", - "private_function_across_module", + "private_import_across_module", "strings_to_concatenate", "strings_with_wrong_placed_whitespace", ] From a4c011ec1aff9fa0772f3558f467876f3b9f0443 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 8 Apr 2020 19:03:19 +0300 Subject: [PATCH 5/7] Checking tseries as well --- ci/code_checks.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index ddb3719786445..5762f91183874 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -119,10 +119,15 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then MSG='Check for use of private import across modules' ; echo $MSG if [[ "$GITHUB_ACTIONS" == "true" ]]; then $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_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_import_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_import_across_module" pandas/core + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" pandas/core/ + RET=$(($RET + $?)) ; echo $MSG "DONE" + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" pandas/tseries/ + RET=$(($RET + $?)) ; echo $MSG "DONE" fi - RET=$(($RET + $?)) ; echo $MSG "DONE" echo "isort --version-number" isort --version-number From ef3d423fbdb86dd9ff17f09b23e8d9cfde8cde80 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 8 Apr 2020 19:07:11 +0300 Subject: [PATCH 6/7] Added more names to filter --- ci/code_checks.sh | 2 ++ scripts/validate_unwanted_patterns.py | 12 +++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 5762f91183874..9c4bc2db00056 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -120,11 +120,13 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then if [[ "$GITHUB_ACTIONS" == "true" ]]; then $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_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_import_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_import_across_module" pandas/core/ RET=$(($RET + $?)) ; echo $MSG "DONE" + $BASE_DIR/scripts/validate_unwanted_patterns.py --validation-type="private_import_across_module" pandas/tseries/ RET=$(($RET + $?)) ; echo $MSG "DONE" fi diff --git a/scripts/validate_unwanted_patterns.py b/scripts/validate_unwanted_patterns.py index ea9875d702a8a..cf6bd3565d1cf 100755 --- a/scripts/validate_unwanted_patterns.py +++ b/scripts/validate_unwanted_patterns.py @@ -26,6 +26,16 @@ "_index_shared_docs", "_merge_doc", "_shared_docs", + "_new_Index", + "_new_PeriodIndex", + "_doc_template", + "_interval_shared_docs", + "_apply_docs", + "_arith_doc_FRAME", + "_flex_comp_doc_FRAME", + "_make_flex_doc", + "_op_descriptions", + "_pipe_template", } @@ -124,7 +134,7 @@ def bare_pytest_raises(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: def private_import_across_module(file_obj: IO[str]) -> Iterable[Tuple[int, str]]: """ - Checking that a private function is not used across modules. + Checking that a private function is not imported across modules. Parameters ---------- From 783f99e3261220d32c6b509293977248de07fc17 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Sat, 2 May 2020 11:39:18 -0700 Subject: [PATCH 7/7] dummy to force CI