diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e683fc50c1c5d..201820c6a8b28 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,6 +30,12 @@ repos: files: ^pandas exclude: ^pandas/tests args: [--select, "ANN001,ANN2", --fix-only, --exit-non-zero-on-fix] + - id: ruff + name: ruff-use-pd_array-in-core + alias: ruff-use-pd_array-in-core + files: ^pandas/core/ + exclude: ^pandas/core/api\.py$ + args: [--select, "ICN001", --exit-non-zero-on-fix] - id: ruff-format exclude: ^scripts - repo: https://github.com/jendrikseipp/vulture @@ -272,13 +278,6 @@ repos: language: python entry: python scripts/validate_unwanted_patterns.py --validation-type="nodefault_used_not_only_for_typing" types: [python] - - id: use-pd_array-in-core - name: Import pandas.array as pd_array in core - language: python - entry: python scripts/use_pd_array_in_core.py - files: ^pandas/core/ - exclude: ^pandas/core/api\.py$ - types: [python] - id: no-return-exception name: Use raise instead of return for exceptions language: pygrep diff --git a/pyproject.toml b/pyproject.toml index 82a9d72c8cc74..5a06e22f4be9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -342,6 +342,9 @@ exclude = [ +[tool.ruff.lint.flake8-import-conventions.aliases] +"pandas.core.construction.array" = "pd_array" + [tool.ruff.per-file-ignores] # relative imports allowed for asv_bench "asv_bench/*" = ["TID", "NPY002"] diff --git a/scripts/tests/test_use_pd_array_in_core.py b/scripts/tests/test_use_pd_array_in_core.py deleted file mode 100644 index f58c92722caad..0000000000000 --- a/scripts/tests/test_use_pd_array_in_core.py +++ /dev/null @@ -1,26 +0,0 @@ -import pytest - -from scripts.use_pd_array_in_core import use_pd_array - -BAD_FILE_0 = "import pandas as pd\npd.array" -BAD_FILE_1 = "\nfrom pandas import array" -GOOD_FILE_0 = "from pandas import array as pd_array" -GOOD_FILE_1 = "from pandas.core.construction import array as pd_array" -PATH = "t.py" - - -@pytest.mark.parametrize("content", [BAD_FILE_0, BAD_FILE_1]) -def test_inconsistent_usage(content, capsys) -> None: - result_msg = ( - "t.py:2:0: Don't use pd.array in core, import array as pd_array instead\n" - ) - with pytest.raises(SystemExit, match=None): - use_pd_array(content, PATH) - expected_msg, _ = capsys.readouterr() - assert result_msg == expected_msg - - -@pytest.mark.parametrize("content", [GOOD_FILE_0, GOOD_FILE_1]) -def test_consistent_usage(content) -> None: - # should not raise - use_pd_array(content, PATH) diff --git a/scripts/use_pd_array_in_core.py b/scripts/use_pd_array_in_core.py deleted file mode 100644 index c9e14dece44e4..0000000000000 --- a/scripts/use_pd_array_in_core.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Check that pandas/core imports pandas.array as pd_array. - -This makes it easier to grep for usage of pandas array. - -This is meant to be run as a pre-commit hook - to run it manually, you can do: - - pre-commit run use-pd_array-in-core --all-files - -""" - -from __future__ import annotations - -import argparse -import ast -import sys -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from collections.abc import Sequence - - -ERROR_MESSAGE = ( - "{path}:{lineno}:{col_offset}: " - "Don't use pd.array in core, import array as pd_array instead\n" -) - - -class Visitor(ast.NodeVisitor): - def __init__(self, path: str) -> None: - self.path = path - - def visit_ImportFrom(self, node: ast.ImportFrom) -> None: - # If array has been imported from somewhere in pandas, - # check it's aliased as pd_array. - if ( - node.module is not None - and node.module.startswith("pandas") - and any(i.name == "array" and i.asname != "pd_array" for i in node.names) - ): - msg = ERROR_MESSAGE.format( - path=self.path, lineno=node.lineno, col_offset=node.col_offset - ) - sys.stdout.write(msg) - sys.exit(1) - super().generic_visit(node) - - def visit_Attribute(self, node: ast.Attribute) -> None: - if ( - isinstance(node.value, ast.Name) - and node.value.id == "pd" - and node.attr == "array" - ): - msg = ERROR_MESSAGE.format( - path=self.path, lineno=node.lineno, col_offset=node.col_offset - ) - sys.stdout.write(msg) - sys.exit(1) - super().generic_visit(node) - - -def use_pd_array(content: str, path: str) -> None: - tree = ast.parse(content) - visitor = Visitor(path) - visitor.visit(tree) - - -def main(argv: Sequence[str] | None = None) -> None: - parser = argparse.ArgumentParser() - parser.add_argument("paths", nargs="*") - args = parser.parse_args(argv) - - for path in args.paths: - with open(path, encoding="utf-8") as fd: - content = fd.read() - use_pd_array(content, path) - - -if __name__ == "__main__": - main()