Skip to content

TST: Added script to enforce usage of match argument for tm.assert_produces_warning #59173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,69 @@ repos:
language: python
files: ^doc/source/whatsnew/v
exclude: ^doc/source/whatsnew/v(0|1|2\.0\.0)
- id: enforce-match-arg-in-assert-produces-warning
name: Enforce the usage of match arg
entry: python scripts/enforce_match_arg_in_assert_produces_warning.py
language: python
files: ^pandas/tests
exclude: |
(?x)
^(
pandas/tests/computation/test_eval.py|
pandas/tests/frame/test_query_eval.py|
pandas/tests/frame/methods/test_drop.py|
pandas/tests/plotting/test_datetimelike.py|
pandas/tests/plotting/frame/test_frame_color.py|
pandas/tests/plotting/test_hist_method.py|
pandas/tests/plotting/test_boxplot_method.py|
pandas/tests/util/test_deprecate_kwarg.py|
pandas/tests/util/test_deprecate.py|
pandas/tests/util/test_assert_produces_warning.py|
pandas/tests/util/test_deprecate_nonkeyword_arguments.py|
pandas/tests/api/test_types.py|
pandas/tests/api/test_api.py|
pandas/tests/strings/test_find_replace.py|
pandas/tests/arithmetic/test_datetime64.py|
pandas/tests/arithmetic/test_timedelta64.py|
pandas/tests/arithmetic/test_period.py|
pandas/tests/tseries/offsets/test_offsets.py|
pandas/tests/indexes/datetimes/methods/test_shift.py|
pandas/tests/extension/test_period.py|
pandas/tests/io/pytables/test_retain_attributes.py|
pandas/tests/scalar/timestamp/methods/test_round.py|
pandas/tests/scalar/timestamp/methods/test_to_pydatetime.py|
pandas/tests/io/test_sql.py|
pandas/tests/reshape/test_pivot.py|
pandas/tests/plotting/frame/test_hist_box_by.py|
pandas/tests/frame/methods/test_reindex_like.py|
pandas/tests/plotting/test_series.py|
pandas/tests/io/parser/test_unsupported.py|
pandas/tests/series/accessors/test_cat_accessor.py|
pandas/tests/test_algos.py|
pandas/tests/indexing/multiindex/test_multiindex.py|
pandas/tests/indexes/multi/test_drop.py|
pandas/tests/plotting/frame/test_frame.py|
pandas/tests/window/test_numba.py|
pandas/tests/reshape/test_cut.py|
pandas/tests/apply/test_str.py|
pandas/tests/indexes/multi/test_indexing.py|
pandas/tests/io/pytables/test_store.py|
pandas/tests/io/pytables/test_put.py|
pandas/tests/io/pytables/test_round_trip.py|
pandas/tests/io/excel/test_readers.py|
pandas/tests/resample/test_datetime_index.py|
pandas/tests/io/parser/test_c_parser_only.py|
pandas/tests/io/test_stata.py|
pandas/tests/plotting/test_misc.py|
pandas/tests/series/methods/test_equals.py|
pandas/tests/frame/test_block_internals.py|
pandas/tests/indexes/multi/test_sorting.py|
pandas/tests/series/methods/test_reindex_like.py|
pandas/tests/extension/test_sparse.py|
pandas/tests/indexes/test_common.py|
pandas/tests/indexes/datetimes/methods/test_round.py|
pandas/tests/indexing/multiindex/test_loc.py|
pandas/tests/frame/indexing/test_insert.py|
pandas/tests/groupby/test_groupby.py|
)$
types: [python]
81 changes: 81 additions & 0 deletions scripts/enforce_match_arg_in_assert_produces_warning.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"""

Enforce that all usages of tm.assert_produces_warning use
the "match" argument. This will help ensure that users always see
the correct warning message.

tm.assert_produces_warning(None) is excluded as no warning is
produced.

"""


import argparse
import ast
from collections.abc import Sequence
import sys

ERROR_MESSAGE = (
"{path}:{lineno}:{col_offset}: "
'"match" argument missing in tm.assert_produces_warning'
"\n"
)


class MatchArgForWarningsChecker(ast.NodeVisitor):
def __init__(self) -> None:
self.error_set = []

def visit_Call(self, node) -> None:
if ( isinstance(node.func, ast.Attribute) and
node.func.attr == "assert_produces_warning"):
# only check for attribute function of class/module tm
if ( isinstance(node.func.value, ast.Name) and
node.func.value.id == "tm" ):
# ignore tm.assert_produces_warning(None)/tm.assert_produces_warning()
if ( len(node.args) == 0 or
(isinstance(node.args[0], ast.Constant) and
node.args[0].value is None) ):
return
if not any(keyword.arg == "match" for keyword in node.keywords):
self.error_set.append((node.lineno, node.col_offset))


# Returns true if a file fails the check
def check_for_match_arg(content: str, filename: str) -> bool:
tree = ast.parse(content)
visitor = MatchArgForWarningsChecker()
visitor.visit(tree)

if len(visitor.error_set) == 0:
return False

for error in visitor.error_set:
msg = ERROR_MESSAGE.format(
lineno=error[0],
col_offset=error[1],
path=filename,
)
sys.stdout.write(msg)

return True


def main(argv: Sequence[str] | None = None) -> None:
parser = argparse.ArgumentParser()
parser.add_argument("paths", nargs="*")

args = parser.parse_args(argv)
isMatchMissing = False

for filename in args.paths:
with open(filename, encoding="utf-8") as fd:
content = fd.read()
isMatchMissing = check_for_match_arg(content, filename) | isMatchMissing

if isMatchMissing:
sys.exit(1)


if __name__ == "__main__":
main()
Loading