|
1 | 1 | # mypy: allow-untyped-defs
|
2 | 2 | from __future__ import annotations
|
3 | 3 |
|
4 |
| -from collections.abc import Callable |
5 | 4 | from collections.abc import Collection
|
6 | 5 | from collections.abc import Mapping
|
7 | 6 | from collections.abc import Sequence
|
|
10 | 9 | import math
|
11 | 10 | from numbers import Complex
|
12 | 11 | import pprint
|
13 |
| -import re |
14 | 12 | import sys
|
15 | 13 | from typing import Any
|
16 |
| -from typing import overload |
17 | 14 | from typing import TYPE_CHECKING
|
18 |
| -from typing import TypeVar |
19 |
| - |
20 |
| -from _pytest._code import ExceptionInfo |
21 |
| -from _pytest.outcomes import fail |
22 |
| -from _pytest.raises_group import RaisesExc |
23 | 15 |
|
24 | 16 |
|
25 | 17 | if TYPE_CHECKING:
|
26 | 18 | from numpy import ndarray
|
27 | 19 |
|
28 |
| - E = TypeVar("E", bound=BaseException, default=BaseException) |
29 |
| - |
30 | 20 |
|
31 | 21 | def _compare_approx(
|
32 | 22 | full_object: object,
|
@@ -778,230 +768,3 @@ def _as_numpy_array(obj: object) -> ndarray | None:
|
778 | 768 | elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"):
|
779 | 769 | return np.asarray(obj)
|
780 | 770 | return None
|
781 |
| - |
782 |
| - |
783 |
| -# builtin pytest.raises helper |
784 |
| -# FIXME: This should probably me moved to 'src/_pytest.raises_group.py' |
785 |
| -# (and rename the file to 'raises.py') |
786 |
| -# since it's much more closely tied to those than to the other stuff in this file. |
787 |
| - |
788 |
| - |
789 |
| -@overload |
790 |
| -def raises( |
791 |
| - expected_exception: type[E] | tuple[type[E], ...], |
792 |
| - *, |
793 |
| - match: str | re.Pattern[str] | None = ..., |
794 |
| - check: Callable[[E], bool] = ..., |
795 |
| -) -> RaisesExc[E]: ... |
796 |
| - |
797 |
| - |
798 |
| -@overload |
799 |
| -def raises( |
800 |
| - *, |
801 |
| - match: str | re.Pattern[str], |
802 |
| - # If exception_type is not provided, check() must do any typechecks itself. |
803 |
| - check: Callable[[BaseException], bool] = ..., |
804 |
| -) -> RaisesExc[BaseException]: ... |
805 |
| - |
806 |
| - |
807 |
| -@overload |
808 |
| -def raises(*, check: Callable[[BaseException], bool]) -> RaisesExc[BaseException]: ... |
809 |
| - |
810 |
| - |
811 |
| -@overload |
812 |
| -def raises( |
813 |
| - expected_exception: type[E] | tuple[type[E], ...], |
814 |
| - func: Callable[..., Any], |
815 |
| - *args: Any, |
816 |
| - **kwargs: Any, |
817 |
| -) -> ExceptionInfo[E]: ... |
818 |
| - |
819 |
| - |
820 |
| -def raises( |
821 |
| - expected_exception: type[E] | tuple[type[E], ...] | None = None, |
822 |
| - *args: Any, |
823 |
| - **kwargs: Any, |
824 |
| -) -> RaisesExc[BaseException] | ExceptionInfo[E]: |
825 |
| - r"""Assert that a code block/function call raises an exception type, or one of its subclasses. |
826 |
| -
|
827 |
| - :param expected_exception: |
828 |
| - The expected exception type, or a tuple if one of multiple possible |
829 |
| - exception types are expected. Note that subclasses of the passed exceptions |
830 |
| - will also match. |
831 |
| -
|
832 |
| - :kwparam str | re.Pattern[str] | None match: |
833 |
| - If specified, a string containing a regular expression, |
834 |
| - or a regular expression object, that is tested against the string |
835 |
| - representation of the exception and its :pep:`678` `__notes__` |
836 |
| - using :func:`re.search`. |
837 |
| -
|
838 |
| - To match a literal string that may contain :ref:`special characters |
839 |
| - <re-syntax>`, the pattern can first be escaped with :func:`re.escape`. |
840 |
| -
|
841 |
| - (This is only used when ``pytest.raises`` is used as a context manager, |
842 |
| - and passed through to the function otherwise. |
843 |
| - When using ``pytest.raises`` as a function, you can use: |
844 |
| - ``pytest.raises(Exc, func, match="passed on").match("my pattern")``.) |
845 |
| -
|
846 |
| - Use ``pytest.raises`` as a context manager, which will capture the exception of the given |
847 |
| - type, or any of its subclasses:: |
848 |
| -
|
849 |
| - >>> import pytest |
850 |
| - >>> with pytest.raises(ZeroDivisionError): |
851 |
| - ... 1/0 |
852 |
| -
|
853 |
| - If the code block does not raise the expected exception (:class:`ZeroDivisionError` in the example |
854 |
| - above), or no exception at all, the check will fail instead. |
855 |
| -
|
856 |
| - You can also use the keyword argument ``match`` to assert that the |
857 |
| - exception matches a text or regex:: |
858 |
| -
|
859 |
| - >>> with pytest.raises(ValueError, match='must be 0 or None'): |
860 |
| - ... raise ValueError("value must be 0 or None") |
861 |
| -
|
862 |
| - >>> with pytest.raises(ValueError, match=r'must be \d+$'): |
863 |
| - ... raise ValueError("value must be 42") |
864 |
| -
|
865 |
| - The ``match`` argument searches the formatted exception string, which includes any |
866 |
| - `PEP-678 <https://peps.python.org/pep-0678/>`__ ``__notes__``: |
867 |
| -
|
868 |
| - >>> with pytest.raises(ValueError, match=r"had a note added"): # doctest: +SKIP |
869 |
| - ... e = ValueError("value must be 42") |
870 |
| - ... e.add_note("had a note added") |
871 |
| - ... raise e |
872 |
| -
|
873 |
| - The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the |
874 |
| - details of the captured exception:: |
875 |
| -
|
876 |
| - >>> with pytest.raises(ValueError) as exc_info: |
877 |
| - ... raise ValueError("value must be 42") |
878 |
| - >>> assert exc_info.type is ValueError |
879 |
| - >>> assert exc_info.value.args[0] == "value must be 42" |
880 |
| -
|
881 |
| - .. warning:: |
882 |
| -
|
883 |
| - Given that ``pytest.raises`` matches subclasses, be wary of using it to match :class:`Exception` like this:: |
884 |
| -
|
885 |
| - # Careful, this will catch ANY exception raised. |
886 |
| - with pytest.raises(Exception): |
887 |
| - some_function() |
888 |
| -
|
889 |
| - Because :class:`Exception` is the base class of almost all exceptions, it is easy for this to hide |
890 |
| - real bugs, where the user wrote this expecting a specific exception, but some other exception is being |
891 |
| - raised due to a bug introduced during a refactoring. |
892 |
| -
|
893 |
| - Avoid using ``pytest.raises`` to catch :class:`Exception` unless certain that you really want to catch |
894 |
| - **any** exception raised. |
895 |
| -
|
896 |
| - .. note:: |
897 |
| -
|
898 |
| - When using ``pytest.raises`` as a context manager, it's worthwhile to |
899 |
| - note that normal context manager rules apply and that the exception |
900 |
| - raised *must* be the final line in the scope of the context manager. |
901 |
| - Lines of code after that, within the scope of the context manager will |
902 |
| - not be executed. For example:: |
903 |
| -
|
904 |
| - >>> value = 15 |
905 |
| - >>> with pytest.raises(ValueError) as exc_info: |
906 |
| - ... if value > 10: |
907 |
| - ... raise ValueError("value must be <= 10") |
908 |
| - ... assert exc_info.type is ValueError # This will not execute. |
909 |
| -
|
910 |
| - Instead, the following approach must be taken (note the difference in |
911 |
| - scope):: |
912 |
| -
|
913 |
| - >>> with pytest.raises(ValueError) as exc_info: |
914 |
| - ... if value > 10: |
915 |
| - ... raise ValueError("value must be <= 10") |
916 |
| - ... |
917 |
| - >>> assert exc_info.type is ValueError |
918 |
| -
|
919 |
| - **Expecting exception groups** |
920 |
| -
|
921 |
| - When expecting exceptions wrapped in :exc:`BaseExceptionGroup` or |
922 |
| - :exc:`ExceptionGroup`, you should instead use :class:`pytest.RaisesGroup`. |
923 |
| -
|
924 |
| - **Using with** ``pytest.mark.parametrize`` |
925 |
| -
|
926 |
| - When using :ref:`pytest.mark.parametrize ref` |
927 |
| - it is possible to parametrize tests such that |
928 |
| - some runs raise an exception and others do not. |
929 |
| -
|
930 |
| - See :ref:`parametrizing_conditional_raising` for an example. |
931 |
| -
|
932 |
| - .. seealso:: |
933 |
| -
|
934 |
| - :ref:`assertraises` for more examples and detailed discussion. |
935 |
| -
|
936 |
| - **Legacy form** |
937 |
| -
|
938 |
| - It is possible to specify a callable by passing a to-be-called lambda:: |
939 |
| -
|
940 |
| - >>> raises(ZeroDivisionError, lambda: 1/0) |
941 |
| - <ExceptionInfo ...> |
942 |
| -
|
943 |
| - or you can specify an arbitrary callable with arguments:: |
944 |
| -
|
945 |
| - >>> def f(x): return 1/x |
946 |
| - ... |
947 |
| - >>> raises(ZeroDivisionError, f, 0) |
948 |
| - <ExceptionInfo ...> |
949 |
| - >>> raises(ZeroDivisionError, f, x=0) |
950 |
| - <ExceptionInfo ...> |
951 |
| -
|
952 |
| - The form above is fully supported but discouraged for new code because the |
953 |
| - context manager form is regarded as more readable and less error-prone. |
954 |
| -
|
955 |
| - .. note:: |
956 |
| - Similar to caught exception objects in Python, explicitly clearing |
957 |
| - local references to returned ``ExceptionInfo`` objects can |
958 |
| - help the Python interpreter speed up its garbage collection. |
959 |
| -
|
960 |
| - Clearing those references breaks a reference cycle |
961 |
| - (``ExceptionInfo`` --> caught exception --> frame stack raising |
962 |
| - the exception --> current frame stack --> local variables --> |
963 |
| - ``ExceptionInfo``) which makes Python keep all objects referenced |
964 |
| - from that cycle (including all local variables in the current |
965 |
| - frame) alive until the next cyclic garbage collection run. |
966 |
| - More detailed information can be found in the official Python |
967 |
| - documentation for :ref:`the try statement <python:try>`. |
968 |
| - """ |
969 |
| - __tracebackhide__ = True |
970 |
| - |
971 |
| - if not args: |
972 |
| - if set(kwargs) - {"match", "check", "expected_exception"}: |
973 |
| - msg = "Unexpected keyword arguments passed to pytest.raises: " |
974 |
| - msg += ", ".join(sorted(kwargs)) |
975 |
| - msg += "\nUse context-manager form instead?" |
976 |
| - raise TypeError(msg) |
977 |
| - |
978 |
| - if expected_exception is None: |
979 |
| - return RaisesExc(**kwargs) |
980 |
| - return RaisesExc(expected_exception, **kwargs) |
981 |
| - |
982 |
| - if not expected_exception: |
983 |
| - raise ValueError( |
984 |
| - f"Expected an exception type or a tuple of exception types, but got `{expected_exception!r}`. " |
985 |
| - f"Raising exceptions is already understood as failing the test, so you don't need " |
986 |
| - f"any special code to say 'this should never raise an exception'." |
987 |
| - ) |
988 |
| - func = args[0] |
989 |
| - if not callable(func): |
990 |
| - raise TypeError(f"{func!r} object (type: {type(func)}) must be callable") |
991 |
| - with RaisesExc(expected_exception) as excinfo: |
992 |
| - func(*args[1:], **kwargs) |
993 |
| - try: |
994 |
| - return excinfo |
995 |
| - finally: |
996 |
| - del excinfo |
997 |
| - |
998 |
| - |
999 |
| -# note: RaisesExc/RaisesGroup uses fail() internally, so this alias |
1000 |
| -# indicates (to [internal] plugins?) that `pytest.raises` will |
1001 |
| -# raise `_pytest.outcomes.Failed`, where |
1002 |
| -# `outcomes.Failed is outcomes.fail.Exception is raises.Exception` |
1003 |
| -# note: this is *not* the same as `_pytest.main.Failed` |
1004 |
| -# note: mypy does not recognize this attribute, and it's not possible |
1005 |
| -# to use a protocol/decorator like the others in outcomes due to |
1006 |
| -# https://github.com/python/mypy/issues/18715 |
1007 |
| -raises.Exception = fail.Exception # type: ignore[attr-defined] |
0 commit comments