Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ repos:
entry: python scripts/validate_min_versions_in_sync.py
language: python
files: ^(ci/deps/actions-.*-minimum_versions\.yaml|pandas/compat/_optional\.py)$
- id: validate-errors-locations
name: Validate errors locations
description: Validate errors are in approriate locations.
entry: python scripts/validate_exception_location.py
language: python
files: ^pandas/
exclude: ^(pandas/_libs/|pandas/tests/|pandas/errors/__init__.py$)
types: [python]
- id: flake8-pyi
name: flake8-pyi
entry: flake8 --extend-ignore=E301,E302,E305,E701,E704
Expand Down
5 changes: 5 additions & 0 deletions doc/source/reference/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,14 @@ Exceptions and warnings
errors.IncompatibilityWarning
errors.IndexingError
errors.InvalidColumnName
errors.InvalidComparison
errors.InvalidIndexError
errors.InvalidVersion
errors.IntCastingNaNError
errors.LossySetitemError
errors.MergeError
errors.NoBufferPresent
errors.NotThisMethod
errors.NullFrequencyError
errors.NumbaUtilError
errors.NumExprClobberingError
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.6.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Other enhancements
- :meth:`.GroupBy.quantile` now preserving nullable dtypes instead of casting to numpy dtypes (:issue:`37493`)
- :meth:`Series.add_suffix`, :meth:`DataFrame.add_suffix`, :meth:`Series.add_prefix` and :meth:`DataFrame.add_prefix` support an ``axis`` argument. If ``axis`` is set, the default behaviour of which axis to consider can be overwritten (:issue:`47819`)
- :func:`assert_frame_equal` now shows the first element where the DataFrames differ, analogously to ``pytest``'s output (:issue:`47910`)
- :class:`.CategoricalConversionWarning`, :class:`.InvalidComparison`, :class:`.InvalidVersion`, :class:`.LossySetitemError`, :class:`.NoBufferPresent`, and :class:`.NotThisMethod` are now exposed in ``pandas.errors`` (:issue:`27656`)
-

.. ---------------------------------------------------------------------------
Expand Down
10 changes: 1 addition & 9 deletions pandas/core/arrays/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
from pandas.compat.numpy import function as nv
from pandas.errors import (
AbstractMethodError,
InvalidComparison,
NullFrequencyError,
PerformanceWarning,
)
Expand Down Expand Up @@ -153,15 +154,6 @@
DatetimeLikeArrayT = TypeVar("DatetimeLikeArrayT", bound="DatetimeLikeArrayMixin")


class InvalidComparison(Exception):
"""
Raised by _validate_comparison_value to indicate to caller it should
return invalid_comparison.
"""

pass


class DatetimeLikeArrayMixin(OpsMixin, NDArrayBackedExtensionArray):
"""
Shared Base/Mixin class for DatetimeArray, TimedeltaArray, PeriodArray
Expand Down
13 changes: 4 additions & 9 deletions pandas/core/dtypes/cast.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@
DtypeObj,
Scalar,
)
from pandas.errors import IntCastingNaNError
from pandas.errors import (
IntCastingNaNError,
LossySetitemError,
)
from pandas.util._exceptions import find_stack_level
from pandas.util._validators import validate_bool_kwarg

Expand Down Expand Up @@ -2098,11 +2101,3 @@ def _dtype_can_hold_range(rng: range, dtype: np.dtype) -> bool:
if not len(rng):
return True
return np.can_cast(rng[0], dtype) and np.can_cast(rng[-1], dtype)


class LossySetitemError(Exception):
"""
Raised when trying to do a __setitem__ on an np.ndarray that is not lossless.
"""

pass
2 changes: 1 addition & 1 deletion pandas/core/interchange/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from pandas._libs.lib import infer_dtype
from pandas._libs.tslibs import iNaT
from pandas.errors import NoBufferPresent
from pandas.util._decorators import cache_readonly

import pandas as pd
Expand All @@ -23,7 +24,6 @@
from pandas.core.interchange.utils import (
ArrowCTypes,
Endianness,
NoBufferPresent,
dtype_to_arrow_c_fmt,
)

Expand Down
4 changes: 0 additions & 4 deletions pandas/core/interchange/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,3 @@ def dtype_to_arrow_c_fmt(dtype: DtypeObj) -> str:
raise NotImplementedError(
f"Conversion of {dtype} to Arrow C format string is not implemented."
)


class NoBufferPresent(Exception):
"""Exception to signal that there is no requested buffer."""
26 changes: 26 additions & 0 deletions pandas/errors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
OutOfBoundsTimedelta,
)

from pandas._version import NotThisMethod
from pandas.util.version import InvalidVersion


class IntCastingNaNError(ValueError):
"""
Expand Down Expand Up @@ -535,6 +538,24 @@ class CategoricalConversionWarning(Warning):
"""


class LossySetitemError(Exception):
"""
Raised when trying to do a __setitem__ on an np.ndarray that is not lossless.
"""


class NoBufferPresent(Exception):
"""
Exception is raised in _get_data_buffer to signal that there is no requested buffer.
"""


class InvalidComparison(Exception):
"""
Exception is raised by _validate_comparison_value to indicate an invalid comparison.
"""


__all__ = [
"AbstractMethodError",
"AccessorRegistrationWarning",
Expand All @@ -550,9 +571,14 @@ class CategoricalConversionWarning(Warning):
"IncompatibilityWarning",
"IntCastingNaNError",
"InvalidColumnName",
"InvalidComparison",
"InvalidIndexError",
"InvalidVersion",
"IndexingError",
"LossySetitemError",
"MergeError",
"NoBufferPresent",
"NotThisMethod",
"NullFrequencyError",
"NumbaUtilError",
"NumExprClobberingError",
Expand Down
47 changes: 26 additions & 21 deletions pandas/tests/test_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,38 @@
@pytest.mark.parametrize(
"exc",
[
"UnsupportedFunctionCall",
"UnsortedIndexError",
"OutOfBoundsDatetime",
"ParserError",
"PerformanceWarning",
"AttributeConflictWarning",
"CSSWarning",
"CategoricalConversionWarning",
"ClosedFileError",
"DataError",
"DatabaseError",
"DtypeWarning",
"EmptyDataError",
"ParserWarning",
"IncompatibilityWarning",
"IndexingError",
"InvalidColumnName",
"InvalidComparison",
"InvalidVersion",
"LossySetitemError",
"MergeError",
"OptionError",
"NumbaUtilError",
"DataError",
"SpecificationError",
"SettingWithCopyError",
"SettingWithCopyWarning",
"NoBufferPresent",
"NotThisMethod",
"NumExprClobberingError",
"IndexingError",
"PyperclipException",
"CSSWarning",
"ClosedFileError",
"NumbaUtilError",
"OptionError",
"OutOfBoundsDatetime",
"ParserError",
"ParserWarning",
"PerformanceWarning",
"PossibleDataLossError",
"IncompatibilityWarning",
"AttributeConflictWarning",
"DatabaseError",
"PossiblePrecisionLoss",
"CategoricalConversionWarning",
"InvalidColumnName",
"PyperclipException",
"SettingWithCopyError",
"SettingWithCopyWarning",
"SpecificationError",
"UnsortedIndexError",
"UnsupportedFunctionCall",
"ValueLabelTypeMismatch",
],
)
Expand Down
2 changes: 1 addition & 1 deletion scripts/pandas_errors_documented.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Check that doc/source/reference/general_utility_functions.rst documents
Check that doc/source/reference/testing.rst documents
all exceptions and warnings in pandas/errors/__init__.py.

This is meant to be run as a pre-commit hook - to run it manually, you can do:
Expand Down
59 changes: 59 additions & 0 deletions scripts/tests/test_validate_exception_location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import pytest

from scripts.validate_exception_location import (
ERROR_MESSAGE,
validate_exception_and_warning_placement,
)

PATH = "t.py"

# ERRORS_IN_TESTING_RST is the set returned when parsing testing.rst for all the
# exceptions and warnings.
CUSTOM_EXCEPTION_NOT_IN_TESTING_RST = "MyException"
CUSTOM_EXCEPTION__IN_TESTING_RST = "MyOldException"
ERRORS_IN_TESTING_RST = {CUSTOM_EXCEPTION__IN_TESTING_RST}

TEST_CODE = """
import numpy as np
import sys

def my_func():
pass

class {custom_name}({error_type}):
pass

"""


# Test with various python-defined exceptions to ensure they are all flagged.
@pytest.fixture(params=["Exception", "ValueError", "Warning", "UserWarning"])
def error_type(request):
return request.param


def test_class_that_inherits_an_exception_and_is_not_in_the_testing_rst_is_flagged(
capsys, error_type
):
content = TEST_CODE.format(
custom_name=CUSTOM_EXCEPTION_NOT_IN_TESTING_RST, error_type=error_type
)
expected_msg = ERROR_MESSAGE.format(errors=CUSTOM_EXCEPTION_NOT_IN_TESTING_RST)
with pytest.raises(SystemExit, match=None):
validate_exception_and_warning_placement(PATH, content, ERRORS_IN_TESTING_RST)
result_msg, _ = capsys.readouterr()
assert result_msg == expected_msg


def test_class_that_inherits_an_exception_but_is_in_the_testing_rst_is_not_flagged(
capsys, error_type
):
content = TEST_CODE.format(
custom_name=CUSTOM_EXCEPTION__IN_TESTING_RST, error_type=error_type
)
validate_exception_and_warning_placement(PATH, content, ERRORS_IN_TESTING_RST)


def test_class_that_does_not_inherit_an_exception_is_not_flagged(capsys):
content = "class MyClass(NonExceptionClass): pass"
validate_exception_and_warning_placement(PATH, content, ERRORS_IN_TESTING_RST)
Loading