Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ name: Publish to PyPI
push:
branches:
- 'master'
tags:
- '*'
workflow_dispatch:

permissions:
Expand Down
24 changes: 22 additions & 2 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ testtools NEWS

Changes and improvements to testtools_, grouped by release.

NEXT
~~~~
2.8.4
~~~~~

Improvements
------------
Expand All @@ -17,6 +17,26 @@ Improvements
results from synchronous Deferreds in tests.
(Jelmer Vernooij, #546)

* Add support for ``unittest.TestCase.subTest``. Failures are reported
individually while the entire test method is still treated as a single test.
(Stephen Finucane, #567)

* Add ``testtools.matchers.test`` module providing a test harness for
users who write their own custom matchers.
(Stephen Finucane)

Changes
-------

* Re-add compat helpers and helper modules that were accidentally removed
in a patch release, breaking API compatibility. These are now deprecated
and will be removed in a future major release.
(Stephen Finucane, #566)

* ``typing-extensions`` is no longer required at runtime; it is only needed
for type checking.
(Jelmer Vernooij, Takashi Kajinami, #569, #571)

2.8.3
~~~~~

Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ twisted = ["Twisted", "fixtures"]
dev = [
"ruff==0.14.11",
"mypy>=1.0.0",
"typing-extensions;python_version<'3.11'",
]

[tool.hatch.version]
Expand Down Expand Up @@ -82,6 +83,8 @@ module = [
# except tests (we're not sadists)
"testtools.twistedsupport.*",
"tests.*",
# NOTE(stephenfin): These are deprecated so we're not going to type them
"testtools.tests.helpers",
]
disallow_untyped_calls = false
disallow_untyped_defs = false
Expand Down
2 changes: 1 addition & 1 deletion tests/matchers/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
_BinaryMismatch,
_NotNearlyEqual,
)
from testtools.matchers.test import TestMatchersInterface

from ..helpers import FullStackRunTest
from ..matchers.helpers import TestMatchersInterface


class Test_BinaryMismatch(TestCase):
Expand Down
3 changes: 1 addition & 2 deletions tests/matchers/test_const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

from testtools import TestCase
from testtools.matchers import Always, Never

from ..matchers.helpers import TestMatchersInterface
from testtools.matchers.test import TestMatchersInterface


class TestAlwaysInterface(TestMatchersInterface, TestCase):
Expand Down
2 changes: 1 addition & 1 deletion tests/matchers/test_datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
MatchesSetwise,
MatchesStructure,
)
from testtools.matchers.test import TestMatchersInterface

from ..helpers import FullStackRunTest
from ..matchers.helpers import TestMatchersInterface


def run_doctest(obj, name):
Expand Down
3 changes: 1 addition & 2 deletions tests/matchers/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
MatchesDict,
_SubDictOf,
)

from ..matchers.helpers import TestMatchersInterface
from testtools.matchers.test import TestMatchersInterface


class TestMatchesAllDictInterface(TestCase, TestMatchersInterface):
Expand Down
2 changes: 1 addition & 1 deletion tests/matchers/test_doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

from testtools import TestCase
from testtools.matchers._doctest import DocTestMatches
from testtools.matchers.test import TestMatchersInterface

from ..helpers import FullStackRunTest
from ..matchers.helpers import TestMatchersInterface


class TestDocTestMatchesInterface(TestCase, TestMatchersInterface):
Expand Down
2 changes: 1 addition & 1 deletion tests/matchers/test_exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
Raises,
raises,
)
from testtools.matchers.test import TestMatchersInterface

from ..helpers import FullStackRunTest
from ..matchers.helpers import TestMatchersInterface


def make_error(type, *args, **kwargs):
Expand Down
2 changes: 1 addition & 1 deletion tests/matchers/test_higherorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
MatchesPredicateWithParams,
Not,
)
from testtools.matchers.test import TestMatchersInterface

from ..helpers import FullStackRunTest
from ..matchers.helpers import TestMatchersInterface


class TestAllMatch(TestCase, TestMatchersInterface):
Expand Down
2 changes: 1 addition & 1 deletion tests/matchers/test_warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
MatchesStructure,
)
from testtools.matchers._warnings import IsDeprecated, WarningMessage, Warnings
from testtools.matchers.test import TestMatchersInterface

from ..helpers import FullStackRunTest
from ..matchers.helpers import TestMatchersInterface


def make_warning(warning_type, message):
Expand Down
39 changes: 39 additions & 0 deletions tests/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import ast
import io
import sys
import traceback

import testtools
from testtools.compat import (
reraise,
text_repr,
unicode_output_stream,
)
Expand Down Expand Up @@ -216,6 +218,43 @@ def test_unicode_examples_multiline(self):
self.assertEqual(ast.literal_eval(actual), u)


class TestReraise(testtools.TestCase):
"""Tests for trivial reraise wrapper needed for Python 2/3 changes"""

def test_exc_info(self):
"""After reraise exc_info matches plus some extra traceback"""
try:
raise ValueError("Bad value")
except ValueError:
_exc_info = sys.exc_info()
try:
reraise(*_exc_info)
except ValueError:
_new_exc_info = sys.exc_info()
self.assertIs(_exc_info[0], _new_exc_info[0])
self.assertIs(_exc_info[1], _new_exc_info[1])
expected_tb = traceback.extract_tb(_exc_info[2])
self.assertEqual(
expected_tb, traceback.extract_tb(_new_exc_info[2])[-len(expected_tb) :]
)

def test_custom_exception_no_args(self):
"""Reraising does not require args attribute to contain params"""

class CustomException(Exception):
"""Exception that expects and sets attrs but not args"""

def __init__(self, value):
Exception.__init__(self)
self.value = value

try:
raise CustomException("Some value")
except CustomException:
_exc_info = sys.exc_info()
self.assertRaises(CustomException, reraise, *_exc_info)


def test_suite():
from unittest import TestLoader

Expand Down
38 changes: 37 additions & 1 deletion testtools/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,45 @@
import codecs
import io
import sys
import types
import unicodedata
import warnings
from io import BytesIO, StringIO # for backwards-compat
from typing import IO
from typing import IO, Any, NoReturn


def reraise(
exc_class: type[BaseException],
exc_obj: BaseException,
exc_tb: types.TracebackType,
_marker: Any = object(),
) -> NoReturn:
"""Re-raise an exception received from sys.exc_info() or similar."""
warnings.warn(
"This is not necessary in Python 3.",
DeprecationWarning,
stacklevel=2,
)
raise exc_obj.with_traceback(exc_tb)


def _u(s: str) -> str:
warnings.warn(
"This is not necessary in Python 3.",
DeprecationWarning,
stacklevel=2,
)
return s


def _b(s: str) -> bytes:
"""A byte literal."""
warnings.warn(
"This is not necessary in Python 3.",
DeprecationWarning,
stacklevel=2,
)
return s.encode("latin-1")


def _slow_escape(text: str) -> str:
Expand Down
11 changes: 6 additions & 5 deletions testtools/matchers/_higherorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
import sys
import types
from collections.abc import Callable, Iterable
from typing import Any, Generic, TypedDict, TypeVar
from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeVar

if sys.version_info >= (3, 11):
from typing import Unpack
else:
from typing_extensions import Unpack
if TYPE_CHECKING:
if sys.version_info >= (3, 11):
from typing import Unpack
else:
from typing_extensions import Unpack

from ._impl import (
Matcher,
Expand Down
File renamed without changes.
Empty file added testtools/tests/__init__.py
Empty file.
Loading
Loading