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