diff options
| author | robot-piglet <[email protected]> | 2025-10-27 15:28:03 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2025-10-27 15:55:09 +0300 |
| commit | c029f40013a315ebe6ea23d33c4562ed10e176a4 (patch) | |
| tree | e755671c7d038af6cdf1688dfb5710b3759e8962 /contrib/python/PyHamcrest/py3/hamcrest | |
| parent | 058dc84c54b72daf9e25b9ae090a80ed843d4cd0 (diff) | |
Intermediate changes
commit_hash:50448cf0b9f7db378645dc682bab1b0bc040f4eb
Diffstat (limited to 'contrib/python/PyHamcrest/py3/hamcrest')
59 files changed, 1212 insertions, 725 deletions
diff --git a/contrib/python/PyHamcrest/py3/hamcrest/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/__init__.py index f45b032075d..b40f70119c4 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/__init__.py @@ -1,8 +1,13 @@ -from __future__ import absolute_import from hamcrest.core import * from hamcrest.library import * +from hamcrest import core, library +from hamcrest._version import version -__version__ = "1.10.1" +__version__ = version __author__ = "Chris Rose" __copyright__ = "Copyright 2020 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [] +__all__.extend(core.__all__) +__all__.extend(library.__all__) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/_version.py b/contrib/python/PyHamcrest/py3/hamcrest/_version.py new file mode 100644 index 00000000000..b2687cd7063 --- /dev/null +++ b/contrib/python/PyHamcrest/py3/hamcrest/_version.py @@ -0,0 +1,5 @@ +# coding: utf-8 +# file generated by setuptools_scm +# don't change, don't track in version control +version = '2.1.0' # pragma: no mutate +version_tuple = (2, 1, 0) # pragma: no mutate diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/core/__init__.py index 779fa723459..a578f365748 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/__init__.py @@ -1,7 +1,24 @@ -from __future__ import absolute_import from hamcrest.core.assert_that import assert_that from hamcrest.core.core import * __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [ + "assert_that", + "all_of", + "any_of", + "anything", + "calling", + "described_as", + "equal_to", + "instance_of", + "is_", + "is_not", + "none", + "not_", + "not_none", + "raises", + "same_instance", +] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/assert_that.py b/contrib/python/PyHamcrest/py3/hamcrest/core/assert_that.py index 8c36ceab764..a31cf3a1b21 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/assert_that.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/assert_that.py @@ -1,5 +1,6 @@ -from __future__ import absolute_import import warnings +from typing import Optional, TypeVar, cast, overload + from hamcrest.core.matcher import Matcher from hamcrest.core.string_description import StringDescription @@ -11,7 +12,20 @@ __unittest = True # py.test integration; hide these frames from tracebacks __tracebackhide__ = True -def assert_that(arg1, arg2=None, arg3=''): +T = TypeVar("T") + + +@overload +def assert_that(actual_or_assertion: T, matcher: Matcher[T], reason: str = "") -> None: + ... + + +@overload +def assert_that(actual_or_assertion: bool, reason: str = "") -> None: + ... + + +def assert_that(actual_or_assertion, matcher=None, reason=""): """Asserts that actual value satisfies matcher. (Can also assert plain boolean condition.) @@ -40,28 +54,27 @@ def assert_that(arg1, arg2=None, arg3=''): writing by being a standalone function. """ - if isinstance(arg2, Matcher): - _assert_match(actual=arg1, matcher=arg2, reason=arg3) + if isinstance(matcher, Matcher): + _assert_match(actual=actual_or_assertion, matcher=matcher, reason=reason) else: - if isinstance(arg1, Matcher): - warnings.warn("arg1 should be boolean, but was {}".format(type(arg1))) - _assert_bool(assertion=arg1, reason=arg2) + if isinstance(actual_or_assertion, Matcher): + warnings.warn("arg1 should be boolean, but was {}".format(type(actual_or_assertion))) + _assert_bool(assertion=cast(bool, actual_or_assertion), reason=cast(str, matcher)) -def _assert_match(actual, matcher, reason): +def _assert_match(actual: T, matcher: Matcher[T], reason: str) -> None: if not matcher.matches(actual): description = StringDescription() - description.append_text(reason) \ - .append_text('\nExpected: ') \ - .append_description_of(matcher) \ - .append_text('\n but: ') + description.append_text(reason).append_text("\nExpected: ").append_description_of( + matcher + ).append_text("\n but: ") matcher.describe_mismatch(actual, description) - description.append_text('\n') + description.append_text("\n") raise AssertionError(description) -def _assert_bool(assertion, reason=None): +def _assert_bool(assertion: bool, reason: Optional[str] = None) -> None: if not assertion: if not reason: - reason = 'Assertion failed' + reason = "Assertion failed" raise AssertionError(reason) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/base_description.py b/contrib/python/PyHamcrest/py3/hamcrest/core/base_description.py index 18b3ee9ee53..e0ceea34ff0 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/base_description.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/base_description.py @@ -1,63 +1,40 @@ -from __future__ import absolute_import -__author__ = "Jon Reid" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" - -import warnings -import six +from typing import Any, Iterable from hamcrest.core.description import Description -from hamcrest.core.selfdescribingvalue import SelfDescribingValue from hamcrest.core.helpers.hasmethod import hasmethod from hamcrest.core.helpers.ismock import ismock +__author__ = "Jon Reid" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" + + class BaseDescription(Description): """Base class for all :py:class:`~hamcrest.core.description.Description` implementations. """ - def append_text(self, text): + def append_text(self, text: str) -> Description: self.append(text) return self - def append_description_of(self, value): - if not ismock(value) and hasmethod(value, 'describe_to'): + def append_description_of(self, value: Any) -> Description: + if not ismock(value) and hasmethod(value, "describe_to"): value.describe_to(self) - elif six.PY3 and isinstance(value, six.text_type): + elif isinstance(value, str): self.append(repr(value)) - elif six.PY2 and isinstance(value, six.binary_type): - self.append_string_in_python_syntax(value) - elif isinstance(value, six.text_type): - self.append_string_in_python_syntax(value) else: description = str(value) - if description[:1] == '<' and description[-1:] == '>': + if description[:1] == "<" and description[-1:] == ">": self.append(description) else: - self.append('<') + self.append("<") self.append(description) - self.append('>') - return self - - def append_value(self, value): - warnings.warn('Call append_description_of instead of append_value', - DeprecationWarning) - if isinstance(value, str): - self.append_string_in_python_syntax(value) - else: - self.append('<') - self.append(str(value)) - self.append('>') + self.append(">") return self - def append_value_list(self, start, separator, end, list): - warnings.warn('Call append_list instead of append_value_list', - DeprecationWarning) - return self.append_list(start, separator, end, - map(SelfDescribingValue, list)) - - def append_list(self, start, separator, end, list): + def append_list(self, start: str, separator: str, end: str, list: Iterable[Any]) -> Description: separate = False self.append(start) @@ -69,25 +46,25 @@ class BaseDescription(Description): self.append(end) return self - def append(self, string): + def append(self, string: str) -> None: """Append the string to the description.""" - raise NotImplementedError('append') + raise NotImplementedError("append") - def append_string_in_python_syntax(self, string): + def append_string_in_python_syntax(self, string: str) -> None: self.append("'") for ch in string: self.append(character_in_python_syntax(ch)) self.append("'") -def character_in_python_syntax(ch): +def character_in_python_syntax(ch: str) -> str: if ch == "'": - return "\'" - elif ch == '\n': - return '\\n' - elif ch == '\r': - return '\\r' - elif ch == '\t': - return '\\t' + return "'" + elif ch == "\n": + return "\\n" + elif ch == "\r": + return "\\r" + elif ch == "\t": + return "\\t" else: return ch diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/base_matcher.py b/contrib/python/PyHamcrest/py3/hamcrest/core/base_matcher.py index 951e2a7b95d..7edc994f9c1 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/base_matcher.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/base_matcher.py @@ -1,13 +1,18 @@ -from __future__ import absolute_import +from textwrap import shorten +from typing import Optional, TypeVar + +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher +from hamcrest.core.string_description import tostring + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.core.matcher import Matcher -from hamcrest.core.string_description import tostring +T = TypeVar("T") -class BaseMatcher(Matcher): +class BaseMatcher(Matcher[T]): """Base class for all :py:class:`~hamcrest.core.matcher.Matcher` implementations. @@ -18,17 +23,26 @@ class BaseMatcher(Matcher): """ - def __str__(self): + def __str__(self) -> str: return tostring(self) - def _matches(self, item): - raise NotImplementedError('_matches') + def __repr__(self) -> str: + """Returns matcher string representation.""" + return "<{0}({1})>".format( + self.__class__.__name__, shorten(tostring(self), 60, placeholder="...") + ) - def matches(self, item, mismatch_description=None): + def _matches(self, item: T) -> bool: + raise NotImplementedError("_matches") + + def matches(self, item: T, mismatch_description: Optional[Description] = None) -> bool: match_result = self._matches(item) if not match_result and mismatch_description: self.describe_mismatch(item, mismatch_description) return match_result - def describe_mismatch(self, item, mismatch_description): - mismatch_description.append_text('was ').append_description_of(item) + def describe_mismatch(self, item: T, mismatch_description: Description) -> None: + mismatch_description.append_text("was ").append_description_of(item) + + def describe_match(self, item: T, match_description: Description) -> None: + match_description.append_text("was ").append_description_of(item) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/compat.py b/contrib/python/PyHamcrest/py3/hamcrest/core/compat.py deleted file mode 100644 index 2c6d1fa74c8..00000000000 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/compat.py +++ /dev/null @@ -1,19 +0,0 @@ -__author__ = "Per Fagrell" -__copyright__ = "Copyright 2013 hamcrest.org" -__license__ = "BSD, see License.txt" - -__all__ = ['is_callable'] - -import sys - -# callable was not part of py3k until 3.2, so we create this -# generic is_callable to use callable if possible, otherwise -# we use generic homebrew. -if sys.version_info[0] == 3 and sys.version_info[1] < 2: - def is_callable(function): - """Return whether the object is callable (i.e., some kind of function).""" - if function is None: - return False - return any("__call__" in klass.__dict__ for klass in type(function).__mro__) -else: - is_callable = callable diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/__init__.py index 38e93e249a7..3bb11209fb5 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/__init__.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import """Fundamental matchers of objects and values, and composite matchers.""" from hamcrest.core.core.allof import all_of @@ -16,3 +15,20 @@ from hamcrest.core.core.raises import calling, raises __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [ + "all_of", + "any_of", + "anything", + "calling", + "described_as", + "equal_to", + "instance_of", + "is_", + "is_not", + "none", + "not_", + "not_none", + "raises", + "same_instance", +] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/allof.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/allof.py index e051f6abb30..ffb62f6c3e0 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/allof.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/allof.py @@ -1,42 +1,48 @@ +from typing import Optional, TypeVar, Union + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +T = TypeVar("T") -class AllOf(BaseMatcher): - def __init__(self, *matchers, **kwargs): +class AllOf(BaseMatcher[T]): + def __init__(self, *matchers: Matcher[T], **kwargs): self.matchers = matchers - self.describe_matcher_in_mismatch = kwargs.pop('describe_matcher_in_mismatch', True) # No keyword-only args in 2.7 :-( - self.describe_all_mismatches = kwargs.pop('describe_all_mismatches', False) + self.describe_matcher_in_mismatch = kwargs.pop( + "describe_matcher_in_mismatch", True + ) # No keyword-only args in 2.7 :-( + self.describe_all_mismatches = kwargs.pop("describe_all_mismatches", False) - def matches(self, item, mismatch_description=None): + def matches(self, item: T, mismatch_description: Optional[Description] = None) -> bool: found_mismatch = False for i, matcher in enumerate(self.matchers): if not matcher.matches(item): if mismatch_description: if self.describe_matcher_in_mismatch: - mismatch_description.append_description_of(matcher) \ - .append_text(' ') + mismatch_description.append_description_of(matcher).append_text(" ") matcher.describe_mismatch(item, mismatch_description) found_mismatch = True if not self.describe_all_mismatches: break elif i < len(self.matchers) - 1 and mismatch_description: - mismatch_description.append_text(' and ') + mismatch_description.append_text(" and ") return not found_mismatch - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: T, mismatch_description: Description) -> None: self.matches(item, mismatch_description) - def describe_to(self, description): - description.append_list('(', ' and ', ')', self.matchers) + def describe_to(self, description: Description) -> None: + description.append_list("(", " and ", ")", self.matchers) -def all_of(*items): +def all_of(*items: Union[Matcher[T], T]) -> Matcher[T]: """Matches if all of the given matchers evaluate to ``True``. :param matcher1,...: A comma-separated list of matchers. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/anyof.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/anyof.py index 7a2bfc6627d..921e3b2f9f5 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/anyof.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/anyof.py @@ -1,27 +1,32 @@ +from typing import TypeVar, Union + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +T = TypeVar("T") -class AnyOf(BaseMatcher): - def __init__(self, *matchers): +class AnyOf(BaseMatcher[T]): + def __init__(self, *matchers: Matcher[T]) -> None: self.matchers = matchers - def _matches(self, item): + def _matches(self, item: T) -> bool: for matcher in self.matchers: if matcher.matches(item): return True return False - def describe_to(self, description): - description.append_list('(', ' or ', ')', self.matchers) + def describe_to(self, description: Description) -> None: + description.append_list("(", " or ", ")", self.matchers) -def any_of(*items): +def any_of(*items: Union[Matcher[T], T]) -> Matcher[T]: """Matches if any of the given matchers evaluate to ``True``. :param matcher1,...: A comma-separated list of matchers. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/described_as.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/described_as.py index 93b4d6ac458..dba2b5ccdd3 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/described_as.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/described_as.py @@ -1,31 +1,35 @@ -from hamcrest.core.base_matcher import BaseMatcher import re +from typing import Any, Optional, Tuple + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +ARG_PATTERN = re.compile("%([0-9]+)") -ARG_PATTERN = re.compile('%([0-9]+)') - - -class DescribedAs(BaseMatcher): - def __init__(self, description_template, matcher, *values): +class DescribedAs(BaseMatcher[Any]): + def __init__( + self, description_template: str, matcher: Matcher[Any], *values: Tuple[Any, ...] + ) -> None: self.template = description_template self.matcher = matcher self.values = values - def matches(self, item, mismatch_description=None): + def matches(self, item: Any, mismatch_description: Optional[Description] = None) -> bool: return self.matcher.matches(item, mismatch_description) - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: Any, mismatch_description: Description) -> None: self.matcher.describe_mismatch(item, mismatch_description) - def describe_to(self, description): + def describe_to(self, description: Description) -> None: text_start = 0 for match in re.finditer(ARG_PATTERN, self.template): - description.append_text(self.template[text_start:match.start()]) + description.append_text(self.template[text_start : match.start()]) arg_index = int(match.group()[1:]) description.append_description_of(self.values[arg_index]) text_start = match.end() @@ -34,7 +38,7 @@ class DescribedAs(BaseMatcher): description.append_text(self.template[text_start:]) -def described_as(description, matcher, *values): +def described_as(description: str, matcher: Matcher[Any], *values) -> Matcher[Any]: """Adds custom failure description to a given matcher. :param description: Overrides the matcher's description. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/future.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/future.py new file mode 100644 index 00000000000..b58bc2a892a --- /dev/null +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/future.py @@ -0,0 +1,137 @@ +import sys +import re +import asyncio +from typing import ( + Optional, + Type, + TypeVar, + Union, + Awaitable, +) + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher + +__author__ = "David Keijser" +__copyright__ = "Copyright 2021 hamcrest.org" +__license__ = "BSD, see License.txt" + +T = TypeVar("T") + +if sys.version_info > (3, 9): + # Same as used in typeshed for asyncio.ensure_future + FutureT = asyncio.Future[T] + FutureLike = Union[asyncio.Future[T], Awaitable[T]] +else: + # Future is not a parametrised type in earlier version of python + FutureT = asyncio.Future + FutureLike = Union[asyncio.Future, Awaitable] + + +class FutureRaising(BaseMatcher[asyncio.Future]): + def __init__( + self, + expected: Type[Exception], + pattern: Optional[str] = None, + matching: Optional[Matcher] = None, + ) -> None: + self.pattern = pattern + self.matcher = matching + self.expected = expected + + def _matches(self, future: asyncio.Future) -> bool: + if not asyncio.isfuture(future): + return False + + if not future.done(): + return False + + if future.cancelled(): + return False + + exc = future.exception() + if exc is None: + return False + + if isinstance(exc, self.expected): + if self.pattern is not None: + if re.search(self.pattern, str(exc)) is None: + return False + if self.matcher is not None: + if not self.matcher.matches(exc): + return False + return True + + return False + + def describe_to(self, description: Description) -> None: + description.append_text("Expected a completed future with exception %s" % self.expected) + + def describe_mismatch(self, future: asyncio.Future, description: Description) -> None: + if not asyncio.isfuture(future): + description.append_text("%s is not a future" % future) + return + + if not future.done(): + description.append_text("%s is not completed yet" % future) + return + + if future.cancelled(): + description.append_text("%s is cancelled" % future) + return + + exc = future.exception() + if exc is None: + description.append_text("No exception raised.") + elif isinstance(exc, self.expected): + if self.pattern is not None or self.matcher is not None: + description.append_text("Correct assertion type raised, but ") + if self.pattern is not None: + description.append_text('the expected pattern ("%s") ' % self.pattern) + if self.pattern is not None and self.matcher is not None: + description.append_text("and ") + if self.matcher is not None: + description.append_description_of(self.matcher) + description.append_text(" ") + description.append_text('not found. Exception message was: "%s"' % str(exc)) + else: + description.append_text("%r of type %s was raised instead" % (exc, type(exc))) + + def describe_match(self, future: asyncio.Future, match_description: Description) -> None: + exc = future.exception() + match_description.append_text("%r of type %s was raised." % (exc, type(exc))) + + +def future_raising( + exception: Type[Exception], pattern=None, matching=None +) -> Matcher[asyncio.Future]: + """Matches a future with the expected exception. + + :param exception: The class of the expected exception + :param pattern: Optional regular expression to match exception message. + :param matching: Optional Hamcrest matchers to apply to the exception. + + Expects the actual to be an already resolved future. The :py:func:`~hamcrest:core.core.future.resolved` helper can be used to wait for a future to resolve. + Optional argument pattern should be a string containing a regular expression. If provided, + the string representation of the actual exception - e.g. `str(actual)` - must match pattern. + + Examples:: + + assert_that(somefuture, future_exception(ValueError)) + assert_that( + await resolved(async_http_get()), + future_exception(HTTPError, matching=has_properties(status_code=500) + ) + """ + return FutureRaising(exception, pattern, matching) + + +async def resolved(obj: FutureLike) -> FutureT: + """Wait for an async operation to finish and return a resolved future object with the result. + + :param obj: A future like object or an awaitable object. + """ + fut = asyncio.ensure_future(obj) + await asyncio.wait([fut]) + return fut diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/is_.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/is_.py index ba11a762aeb..dafe41cd553 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/is_.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/is_.py @@ -1,35 +1,65 @@ -from __future__ import absolute_import -__author__ = "Jon Reid" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" +from typing import Optional, Type, TypeVar, overload, Any from hamcrest.core.base_matcher import BaseMatcher -from hamcrest.core.helpers.wrap_matcher import wrap_matcher, is_matchable_type +from hamcrest.core.description import Description +from hamcrest.core.helpers.wrap_matcher import is_matchable_type, wrap_matcher +from hamcrest.core.matcher import Matcher + from .isinstanceof import instance_of +__author__ = "Jon Reid" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" -class Is(BaseMatcher): +T = TypeVar("T") - def __init__(self, matcher): + +class Is(BaseMatcher[T]): + def __init__(self, matcher: Matcher[T]) -> None: self.matcher = matcher - def matches(self, item, mismatch_description=None): + def matches(self, item: T, mismatch_description: Optional[Description] = None) -> bool: return self.matcher.matches(item, mismatch_description) - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: T, mismatch_description: Description) -> None: return self.matcher.describe_mismatch(item, mismatch_description) - def describe_to(self, description): + def describe_to(self, description: Description): description.append_description_of(self.matcher) -def wrap_value_or_type(x): +@overload +def _wrap_value_or_type(x: Type) -> Matcher[object]: + ... + + +@overload +def _wrap_value_or_type(x: T) -> Matcher[T]: + ... + + +def _wrap_value_or_type(x): if is_matchable_type(x): return instance_of(x) else: return wrap_matcher(x) +@overload +def is_(x: Type) -> Matcher[Any]: + ... + + +@overload +def is_(x: Matcher[T]) -> Matcher[T]: + ... + + +@overload +def is_(x: T) -> Matcher[T]: + ... + + def is_(x): """Decorates another matcher, or provides shortcuts to the frequently used ``is(equal_to(x))`` and ``is(instance_of(x))``. @@ -73,4 +103,4 @@ def is_(x): depending on context. """ - return Is(wrap_value_or_type(x)) + return Is(_wrap_value_or_type(x)) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isanything.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isanything.py index f916811bc97..bed86d82a37 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isanything.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isanything.py @@ -1,25 +1,26 @@ +from typing import Any, Optional + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class IsAnything(BaseMatcher): - - def __init__(self, description): - self.description = description - if not description: - self.description = 'ANYTHING' +class IsAnything(BaseMatcher[Any]): + def __init__(self, description: Optional[str]) -> None: + self.description: str = description or "ANYTHING" - def _matches(self, item): + def _matches(self, item: Any) -> bool: return True - def describe_to(self, description): + def describe_to(self, description: Description) -> None: description.append_text(self.description) -def anything(description=None): +def anything(description: Optional[str] = None) -> Matcher[Any]: """Matches anything. :param description: Optional string used to describe this matcher. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isequal.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isequal.py index 119fd58a482..18160919c17 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isequal.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isequal.py @@ -1,29 +1,31 @@ -__author__ = "Jon Reid" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" +from typing import Any from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.matcher import Matcher +__author__ = "Jon Reid" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" -class IsEqual(BaseMatcher): - def __init__(self, equals): +class IsEqual(BaseMatcher[Any]): + def __init__(self, equals: Any) -> None: self.object = equals - def _matches(self, item): + def _matches(self, item: Any) -> bool: return item == self.object - def describe_to(self, description): + def describe_to(self, description: Description) -> None: nested_matcher = isinstance(self.object, Matcher) if nested_matcher: - description.append_text('<') + description.append_text("<") description.append_description_of(self.object) if nested_matcher: - description.append_text('>') + description.append_text(">") -def equal_to(obj): +def equal_to(obj: Any) -> Matcher[Any]: """Matches if object is equal to a given object. :param obj: The object to compare against as the expected value. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isinstanceof.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isinstanceof.py index f8eb4a2fd10..e1a077bb0cb 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isinstanceof.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isinstanceof.py @@ -1,32 +1,33 @@ +from typing import Type + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import is_matchable_type +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -import types - -class IsInstanceOf(BaseMatcher): - def __init__(self, expected_type): +class IsInstanceOf(BaseMatcher[object]): + def __init__(self, expected_type: Type) -> None: if not is_matchable_type(expected_type): - raise TypeError('IsInstanceOf requires type or a tuple of classes and types') + raise TypeError("IsInstanceOf requires type or a tuple of classes and types") self.expected_type = expected_type - def _matches(self, item): + def _matches(self, item: object) -> bool: return isinstance(item, self.expected_type) - def describe_to(self, description): + def describe_to(self, description: Description) -> None: try: type_description = self.expected_type.__name__ except AttributeError: type_description = "one of %s" % ",".join(str(e) for e in self.expected_type) - description.append_text('an instance of ') \ - .append_text(type_description) + description.append_text("an instance of ").append_text(type_description) -def instance_of(atype): +def instance_of(atype: Type) -> Matcher[object]: """Matches if object is an instance of, or inherits from, a given type. :param atype: The type to compare against as the expected type or a tuple diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnone.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnone.py index 511fd5ae461..1b4fbc123ae 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnone.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnone.py @@ -1,26 +1,29 @@ -from __future__ import absolute_import -__author__ = "Jon Reid" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" +from typing import Any, Optional from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher + from .isnot import is_not +__author__ = "Jon Reid" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" -class IsNone(BaseMatcher): - def _matches(self, item): +class IsNone(BaseMatcher[Optional[Any]]): + def _matches(self, item: Any) -> bool: return item is None - def describe_to(self, description): - description.append_text('None') + def describe_to(self, description: Description) -> None: + description.append_text("None") -def none(): +def none() -> Matcher[Optional[Any]]: """Matches if object is ``None``.""" return IsNone() -def not_none(): +def not_none() -> Matcher[Optional[Any]]: """Matches if object is not ``None``.""" return is_not(none()) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnot.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnot.py index 7567e6f325d..de26f68398d 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnot.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/isnot.py @@ -1,33 +1,61 @@ -from __future__ import absolute_import +from typing import Type, TypeVar, Union, overload + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.helpers.wrap_matcher import is_matchable_type, wrap_matcher +from hamcrest.core.matcher import Matcher + +from .isinstanceof import instance_of + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.core.base_matcher import BaseMatcher, Matcher -from hamcrest.core.helpers.wrap_matcher import wrap_matcher, is_matchable_type -from .isequal import equal_to -from .isinstanceof import instance_of - +T = TypeVar("T") -class IsNot(BaseMatcher): - def __init__(self, matcher): +class IsNot(BaseMatcher[T]): + def __init__(self, matcher: Matcher[T]) -> None: self.matcher = matcher - def _matches(self, item): + def _matches(self, item: T) -> bool: return not self.matcher.matches(item) - def describe_to(self, description): - description.append_text('not ').append_description_of(self.matcher) + def describe_to(self, description: Description) -> None: + description.append_text("not ").append_description_of(self.matcher) + + def describe_mismatch(self, item: T, mismatch_description: Description) -> None: + mismatch_description.append_text("but ") + self.matcher.describe_match(item, mismatch_description) + +@overload +def _wrap_value_or_type(x: Type) -> Matcher[object]: + ... -def wrap_value_or_type(x): + +@overload +def _wrap_value_or_type(x: T) -> Matcher[T]: + ... + + +def _wrap_value_or_type(x): if is_matchable_type(x): return instance_of(x) else: return wrap_matcher(x) +@overload +def is_not(match: Type) -> Matcher[object]: + ... + + +@overload +def is_not(match: Union[Matcher[T], T]) -> Matcher[T]: + ... + + def is_not(match): """Inverts the given matcher to its logical negation. @@ -44,9 +72,10 @@ def is_not(match): assert_that(cheese, is_not(smelly)) """ - return IsNot(wrap_value_or_type(match)) + return IsNot(_wrap_value_or_type(match)) + -def not_(match): +def not_(match: Union[Matcher[T], T]) -> Matcher[T]: """Alias of :py:func:`is_not` for better readability of negations. Examples:: diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/issame.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/issame.py index b1f85427d7a..d4269444e6c 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/issame.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/issame.py @@ -1,33 +1,36 @@ +from typing import TypeVar + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.core.base_matcher import BaseMatcher - +T = TypeVar("T") -class IsSame(BaseMatcher): - def __init__(self, object): - self.object = object +class IsSame(BaseMatcher[T]): + def __init__(self, obj: T) -> None: + self.object = obj - def _matches(self, item): + def _matches(self, item: T) -> bool: return item is self.object - def describe_to(self, description): - description.append_text('same instance as ') \ - .append_text(hex(id(self.object))) \ - .append_text(' ') \ - .append_description_of(self.object) + def describe_to(self, description: Description) -> None: + description.append_text("same instance as ").append_text(hex(id(self.object))).append_text( + " " + ).append_description_of(self.object) - def describe_mismatch(self, item, mismatch_description): - mismatch_description.append_text('was ') + def describe_mismatch(self, item: T, mismatch_description: Description) -> None: + mismatch_description.append_text("was ") if item is not None: - mismatch_description.append_text(hex(id(item))) \ - .append_text(' ') + mismatch_description.append_text(hex(id(item))).append_text(" ") mismatch_description.append_description_of(item) -def same_instance(obj): +def same_instance(obj: T) -> Matcher[T]: """Matches if evaluated object is the same instance as a given object. :param obj: The object to compare against as the expected value. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/core/raises.py b/contrib/python/PyHamcrest/py3/hamcrest/core/core/raises.py index 699a1ccc91d..dddbcb59093 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/core/raises.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/core/raises.py @@ -1,32 +1,40 @@ -from weakref import ref import re import sys +from typing import Any, Callable, Mapping, Optional, Tuple, Type, cast +from weakref import ref + from hamcrest.core.base_matcher import BaseMatcher -from hamcrest.core.helpers.wrap_matcher import wrap_matcher -from hamcrest.core.compat import is_callable +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Per Fagrell" __copyright__ = "Copyright 2013 hamcrest.org" __license__ = "BSD, see License.txt" -class Raises(BaseMatcher): - def __init__(self, expected, pattern=None, matcher=None): +class Raises(BaseMatcher[Callable[..., Any]]): + def __init__( + self, + expected: Type[Exception], + pattern: Optional[str] = None, + matching: Optional[Matcher] = None, + matcher: Optional[Matcher] = None, + ) -> None: self.pattern = pattern + self.matcher = matching or matcher self.expected = expected - self.actual = None - self.function = None - self.matcher = matcher + self.actual: Optional[BaseException] = None + self.function: Optional[Callable[..., Any]] = None self.actual_return_value = None - def _matches(self, function): - if not is_callable(function): + def _matches(self, function: Callable[..., Any]) -> bool: + if not callable(function): return False - self.function = ref(function) + self.function = cast(Callable[..., Any], ref(function)) return self._call_function(function) - def _call_function(self, function): + def _call_function(self, function: Callable[..., Any]) -> bool: self.actual = None try: self.actual_return_value = function() @@ -35,22 +43,23 @@ class Raises(BaseMatcher): if isinstance(self.actual, self.expected): if self.pattern is not None: - return ( - re.search(self.pattern, str(self.actual)) is not None - and (self.matcher is None or self.matcher.matches(self.actual)) - ) - return self.matcher is None or self.matcher.matches(self.actual) + if re.search(self.pattern, str(self.actual)) is None: + return False + if self.matcher is not None: + if not self.matcher.matches(self.actual): + return False + return True return False - def describe_to(self, description): - description.append_text('Expected a callable raising %s' % self.expected) + def describe_to(self, description: Description) -> None: + description.append_text("Expected a callable raising %s" % self.expected) if self.matcher is not None: description.append_text("\n and ") description.append_description_of(self.matcher) - def describe_mismatch(self, item, description): - if not is_callable(item): - description.append_text('%s is not callable' % item) + def describe_mismatch(self, item, description: Description) -> None: + if not callable(item): + description.append_text("%s is not callable" % item) return function = None if self.function is None else self.function() @@ -60,24 +69,36 @@ class Raises(BaseMatcher): return if self.actual is None: - description.append_text('No exception raised and actual return value = ') - description.append_value(self.actual_return_value) + description.append_text("No exception raised and actual return value = '{}'".format(self.actual_return_value)) elif isinstance(self.actual, self.expected): - if self.pattern is not None: - description.append_text('Correct assertion type raised, but the expected pattern ("%s") not found.' % self.pattern) - description.append_text('\n message was: "%s"' % str(self.actual)) - if self.matcher is not None: - description.append_text("\nAdditional exception matcher: ") - self.matcher.describe_mismatch(self.actual, description) + if self.pattern is not None or self.matcher is not None: + description.append_text("Correct assertion type raised, but ") + if self.pattern is not None: + description.append_text('the expected pattern ("%s") ' % self.pattern) + if self.pattern is not None and self.matcher is not None: + description.append_text("and ") + if self.matcher is not None: + description.append_description_of(self.matcher) + description.append_text(" ") + description.append_text('not found. Exception message was: "%s"' % str(self.actual)) else: - description.append_text('%r of type %s was raised instead' % (self.actual, type(self.actual))) + description.append_text( + "%r of type %s was raised instead" % (self.actual, type(self.actual)) + ) + + def describe_match(self, item, match_description: Description) -> None: + self._call_function(item) + match_description.append_text( + "%r of type %s was raised." % (self.actual, type(self.actual)) + ) -def raises(exception, pattern=None, matcher=None): +def raises(exception: Type[Exception], pattern=None, matching=None, matcher=None) -> Matcher[Callable[..., Any]]: """Matches if the called function raised the expected exception. :param exception: The class of the expected exception :param pattern: Optional regular expression to match exception message. + :param matching: Optional Hamcrest matchers to apply to the exception. Expects the actual to be wrapped by using :py:func:`~hamcrest.core.core.raises.calling`, or a callable taking no arguments. @@ -88,15 +109,19 @@ def raises(exception, pattern=None, matcher=None): assert_that(calling(int).with_args('q'), raises(TypeError)) assert_that(calling(parse, broken_input), raises(ValueError)) + assert_that( + calling(valid_user, bad_json), + raises(HTTPError, matching=has_properties(status_code=500) + ) """ - return Raises(exception, pattern, matcher) + return Raises(exception, pattern, matching, matcher) class DeferredCallable(object): - def __init__(self, func): + def __init__(self, func: Callable[..., Any]): self.func = func - self.args = tuple() - self.kwargs = {} + self.args: Tuple[Any, ...] = tuple() + self.kwargs: Mapping[str, Any] = {} def __call__(self): self.func(*self.args, **self.kwargs) @@ -107,7 +132,7 @@ class DeferredCallable(object): return self -def calling(func): +def calling(func: Callable[..., Any]) -> DeferredCallable: """Wrapper for function call that delays the actual execution so that :py:func:`~hamcrest.core.core.raises.raises` matcher can catch any thrown exception. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/description.py b/contrib/python/PyHamcrest/py3/hamcrest/core/description.py index 6201b7f70f9..6f22414bfda 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/description.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/description.py @@ -1,9 +1,11 @@ +from typing import Any, Iterable + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class Description(object): +class Description: """A description of a :py:class:`~hamcrest.core.matcher.Matcher`. A :py:class:`~hamcrest.core.matcher.Matcher` will describe itself to a @@ -11,15 +13,15 @@ class Description(object): """ - def append_text(self, text): + def append_text(self, text: str) -> "Description": """Appends some plain text to the description. :returns: ``self``, for chaining """ - raise NotImplementedError('append_text') + raise NotImplementedError("append_text") - def append_description_of(self, value): + def append_description_of(self, value: Any) -> "Description": """Appends description of given value to this description. If the value implements @@ -29,21 +31,11 @@ class Description(object): :returns: ``self``, for chaining """ - raise NotImplementedError('append_description_of') - - def append_value(self, value): - """Appends an arbitary value to the description. - - **Deprecated:** Call - :py:meth:`~hamcrest.core.description.Description.append_description_of` - instead. - - :returns: ``self``, for chaining - - """ - raise NotImplementedError('append_value') + raise NotImplementedError("append_description_of") - def append_list(self, start, separator, end, list): + def append_list( + self, start: str, separator: str, end: str, list: Iterable[Any] + ) -> "Description": """Appends a list of objects to the description. :param start: String that will begin the list description. @@ -55,4 +47,4 @@ class Description(object): :returns: ``self``, for chaining """ - raise NotImplementedError('append_list') + raise NotImplementedError("append_list") diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/hasmethod.py b/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/hasmethod.py index a1f3bfb1549..fcf41208b9d 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/hasmethod.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/hasmethod.py @@ -3,7 +3,7 @@ __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -def hasmethod(obj, methodname): +def hasmethod(obj: object, methodname: str) -> bool: """Does ``obj`` have a method named ``methodname``?""" if not hasattr(obj, methodname): diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/ismock.py b/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/ismock.py index 318e0d4f9cb..56f24f4ab51 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/ismock.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/ismock.py @@ -1,15 +1,19 @@ -MOCKTYPES = () +from typing import Any, List, Type + +MOCKTYPES: List[Type] = [] try: from mock import Mock - MOCKTYPES += (Mock,) + + MOCKTYPES += [Mock] except ImportError: pass try: from unittest.mock import Mock - MOCKTYPES += (Mock,) + + MOCKTYPES += [Mock] except ImportError: pass -def ismock(obj): - return isinstance(obj, MOCKTYPES) +def ismock(obj: Any) -> bool: + return isinstance(obj, tuple(MOCKTYPES)) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/wrap_matcher.py b/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/wrap_matcher.py index 587ae4c6101..b2574203a86 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/wrap_matcher.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/helpers/wrap_matcher.py @@ -1,4 +1,4 @@ -import six +from typing import Type, TypeVar, Union from hamcrest.core.base_matcher import Matcher from hamcrest.core.core.isequal import equal_to @@ -7,9 +7,10 @@ __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -import types +T = TypeVar("T") -def wrap_matcher(x): + +def wrap_matcher(x: Union[Matcher[T], T]) -> Matcher[T]: """Wraps argument in a matcher, if necessary. :returns: the argument as-is if it is already a matcher, otherwise wrapped @@ -21,11 +22,9 @@ def wrap_matcher(x): else: return equal_to(x) -def is_matchable_type(expected_type): - if isinstance(expected_type, type): - return True - if isinstance(expected_type, six.class_types): +def is_matchable_type(expected_type: Type) -> bool: + if isinstance(expected_type, type): return True if isinstance(expected_type, tuple) and all(map(is_matchable_type, expected_type)): diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/matcher.py b/contrib/python/PyHamcrest/py3/hamcrest/core/matcher.py index 81ee27c6d9d..7ee5ece12f3 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/matcher.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/matcher.py @@ -1,12 +1,17 @@ -from __future__ import absolute_import +from typing import Generic, Optional, TypeVar + +from hamcrest.core.description import Description + from .selfdescribing import SelfDescribing __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +T = TypeVar("T") + -class Matcher(SelfDescribing): +class Matcher(Generic[T], SelfDescribing): """A matcher over acceptable values. A matcher is able to describe itself to give feedback when it fails. @@ -20,7 +25,7 @@ class Matcher(SelfDescribing): """ - def matches(self, item, mismatch_description=None): + def matches(self, item: T, mismatch_description: Optional[Description] = None) -> bool: """Evaluates the matcher for argument item. If a mismatch is detected and argument ``mismatch_description`` is @@ -28,12 +33,13 @@ class Matcher(SelfDescribing): accepted the item. :param item: The object against which the matcher is evaluated. + :param mismatch_description: :returns: ``True`` if ``item`` matches, otherwise ``False``. """ - raise NotImplementedError('matches') + raise NotImplementedError("matches") - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: T, mismatch_description: Description) -> None: """Generates a description of why the matcher has not accepted the item. @@ -49,4 +55,20 @@ class Matcher(SelfDescribing): to. """ - raise NotImplementedError('describe_mismatch') + raise NotImplementedError("describe_mismatch") + + def describe_match(self, item: T, match_description: Description) -> None: + """Generates a description of why the matcher has accepted the item. + + The description may be part of a larger description of why a matching + failed, so it should be concise. + + This method assumes that ``matches(item)`` is ``True``, but will not + check this. + + :param item: The item that the + :py:class:`~hamcrest.core.matcher.Matcher` has accepted. + :param match_description: The description to be built or appended to. + + """ + raise NotImplementedError("describe_match") diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribing.py b/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribing.py index e77b0e0fdb6..d57cb6ef0c0 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribing.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribing.py @@ -1,12 +1,14 @@ +from hamcrest.core.description import Description + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class SelfDescribing(object): +class SelfDescribing: """The ability of an object to describe itself.""" - def describe_to(self, description): + def describe_to(self, description: Description) -> None: """Generates a description of the object. The description may be part of a description of a larger object of @@ -15,4 +17,4 @@ class SelfDescribing(object): :param description: The description to be built or appended to. """ - raise NotImplementedError('describe_to') + raise NotImplementedError("describe_to") diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribingvalue.py b/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribingvalue.py index 7f471e04f2d..148ca01f4f6 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribingvalue.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/selfdescribingvalue.py @@ -1,6 +1,8 @@ -from hamcrest.core.selfdescribing import SelfDescribing - import warnings +from typing import Any + +from hamcrest.core.description import Description +from hamcrest.core.selfdescribing import SelfDescribing __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" @@ -17,11 +19,10 @@ class SelfDescribingValue(SelfDescribing): """ - def __init__(self, value): - warnings.warn('SelfDescribingValue no longer needed', - DeprecationWarning) + def __init__(self, value: Any) -> None: + warnings.warn("SelfDescribingValue no longer needed", DeprecationWarning) self.value = value - def describe_to(self, description): + def describe_to(self, description: Description) -> None: """Generates a description of the value.""" description.append_description_of(self.value) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/core/string_description.py b/contrib/python/PyHamcrest/py3/hamcrest/core/string_description.py index 172dfb4ff22..96fbb26080d 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/core/string_description.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/core/string_description.py @@ -1,7 +1,4 @@ -from __future__ import absolute_import - -import codecs -import six +from hamcrest.core.selfdescribing import SelfDescribing from .base_description import BaseDescription @@ -10,7 +7,7 @@ __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -def tostring(selfdescribing): +def tostring(selfdescribing: SelfDescribing) -> str: """Returns the description of a :py:class:`~hamcrest.core.selfdescribing.SelfDescribing` object as a string. @@ -27,18 +24,12 @@ class StringDescription(BaseDescription): """ - def __init__(self): - self.out = '' + def __init__(self) -> None: + self.out = "" - def __str__(self): + def __str__(self) -> str: """Returns the description.""" return self.out - def append(self, string): - if six.PY3: - self.out += str(string) - else: - if isinstance(string, unicode): - self.out += string - else: - self.out += unicode(string, errors="ignore") + def append(self, string: str) -> None: + self.out += str(string) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/library/__init__.py index d5f909c9216..fb02c2bbb53 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/__init__.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import """Library of Matcher implementations.""" from hamcrest.core import * @@ -13,33 +12,33 @@ __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" __all__ = [ - 'has_entry', - 'has_entries', - 'has_key', - 'has_value', - 'is_in', - 'empty', - 'has_item', - 'has_items', - 'contains_inanyorder', - 'contains', - 'contains_exactly', - 'only_contains', - 'match_equality', - 'matches_regexp', - 'close_to', - 'greater_than', - 'greater_than_or_equal_to', - 'less_than', - 'less_than_or_equal_to', - 'has_length', - 'has_property', - 'has_properties', - 'has_string', - 'equal_to_ignoring_case', - 'equal_to_ignoring_whitespace', - 'contains_string', - 'ends_with', - 'starts_with', - 'string_contains_in_order', + "has_entry", + "has_entries", + "has_key", + "has_value", + "is_in", + "empty", + "has_item", + "has_items", + "contains_inanyorder", + "contains", + "contains_exactly", + "only_contains", + "match_equality", + "matches_regexp", + "close_to", + "greater_than", + "greater_than_or_equal_to", + "less_than", + "less_than_or_equal_to", + "has_length", + "has_property", + "has_properties", + "has_string", + "equal_to_ignoring_case", + "equal_to_ignoring_whitespace", + "contains_string", + "ends_with", + "starts_with", + "string_contains_in_order", ] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/__init__.py index f910e973259..bf07a66e624 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/__init__.py @@ -1,5 +1,5 @@ """Matchers of collections.""" -from __future__ import absolute_import +from .is_empty import empty from .isdict_containing import has_entry from .isdict_containingentries import has_entries from .isdict_containingkey import has_key @@ -9,8 +9,22 @@ from .issequence_containing import has_item, has_items from .issequence_containinginanyorder import contains_inanyorder from .issequence_containinginorder import contains, contains_exactly from .issequence_onlycontaining import only_contains -from .is_empty import empty __author__ = "Chris Rose" __copyright__ = "Copyright 2013 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [ + "contains", + "contains_exactly", + "contains_inanyorder", + "empty", + "has_entries", + "has_entry", + "has_item", + "has_items", + "has_key", + "has_value", + "is_in", + "only_contains", +] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/is_empty.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/is_empty.py index bc99b633730..cff60d636d0 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/is_empty.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/is_empty.py @@ -1,33 +1,34 @@ +from typing import Optional, Sized + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Chris Rose" __copyright__ = "Copyright 2012 hamcrest.org" __license__ = "BSD, see License.txt" -class IsEmpty(BaseMatcher): - - def matches(self, item, mismatch_description=None): +class IsEmpty(BaseMatcher[Sized]): + def matches(self, item: Sized, mismatch_description: Optional[Description] = None) -> bool: try: if len(item) == 0: return True if mismatch_description: - mismatch_description \ - .append_text('has %d item(s)' % len(item)) + mismatch_description.append_text("has %d item(s)" % len(item)) except TypeError: if mismatch_description: - mismatch_description \ - .append_text('does not support length') + mismatch_description.append_text("does not support length") - return False + return False - def describe_to(self, description): - description.append_text('an empty collection') + def describe_to(self, description: Description) -> None: + description.append_text("an empty collection") -def empty(): +def empty() -> Matcher[Sized]: """ This matcher matches any collection-like object that responds to the __len__ method, and has a length of 0. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containing.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containing.py index 95281973fb5..cfe1a5e86ae 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containing.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containing.py @@ -1,34 +1,69 @@ +from typing import Hashable, Mapping, MutableMapping, TypeVar, Union + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.hasmethod import hasmethod from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class IsDictContaining(BaseMatcher): +K = TypeVar("K", bound=Hashable) # TODO - covariant? +V = TypeVar("V") + - def __init__(self, key_matcher, value_matcher): +class IsDictContaining(BaseMatcher[Mapping[K, V]]): + def __init__(self, key_matcher: Matcher[K], value_matcher: Matcher[V]) -> None: self.key_matcher = key_matcher self.value_matcher = value_matcher - def _matches(self, dictionary): - if hasmethod(dictionary, 'items'): - for key, value in dictionary.items(): + def _matches(self, item: Mapping[K, V]) -> bool: + if hasmethod(item, "items"): + for key, value in item.items(): if self.key_matcher.matches(key) and self.value_matcher.matches(value): return True return False - def describe_to(self, description): - description.append_text('a dictionary containing [') \ - .append_description_of(self.key_matcher) \ - .append_text(': ') \ - .append_description_of(self.value_matcher) \ - .append_text(']') + def describe_to(self, description: Description) -> None: + description.append_text("a dictionary containing [").append_description_of( + self.key_matcher + ).append_text(": ").append_description_of(self.value_matcher).append_text("]") + + def describe_mismatch(self, item: Mapping[K, V], mismatch_description: Description) -> None: + key_matches = self._matching_keys(item) + if len(key_matches) == 1: + key, value = key_matches.popitem() + mismatch_description.append_text("value for ").append_description_of(key).append_text( + " " + ) + self.value_matcher.describe_mismatch(value, mismatch_description) + else: + super().describe_mismatch(item, mismatch_description) + + def describe_match(self, item: Mapping[K, V], match_description: Description) -> None: + key_matches = self._matching_keys(item) + if len(key_matches) == 1: + key, value = key_matches.popitem() + match_description.append_text("value for ").append_description_of(key).append_text(" ") + self.value_matcher.describe_mismatch(value, match_description) + else: + super().describe_match(item, match_description) + + def _matching_keys(self, item) -> MutableMapping[K, V]: + key_matches: MutableMapping[K, V] = {} + if hasmethod(item, "items"): + for key, value in item.items(): + if self.key_matcher.matches(key): + key_matches[key] = value + return key_matches -def has_entry(key_match, value_match): +def has_entry( + key_match: Union[K, Matcher[K]], value_match: Union[V, Matcher[V]] +) -> Matcher[Mapping[K, V]]: """Matches if dictionary contains key-value entry satisfying a given pair of matchers. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingentries.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingentries.py index eb83ade52de..79341ff9310 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingentries.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingentries.py @@ -1,70 +1,92 @@ +from typing import Any, Hashable, Mapping, Optional, TypeVar, Union, overload + from hamcrest.core.base_matcher import BaseMatcher -from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +K = TypeVar("K", bound=Hashable) +V = TypeVar("V") -class IsDictContainingEntries(BaseMatcher): - def __init__(self, value_matchers): +class IsDictContainingEntries(BaseMatcher[Mapping[K, V]]): + def __init__(self, value_matchers) -> None: self.value_matchers = sorted(value_matchers.items()) - def _not_a_dictionary(self, dictionary, mismatch_description): + def _not_a_dictionary( + self, item: Mapping[K, V], mismatch_description: Optional[Description] + ) -> bool: if mismatch_description: - mismatch_description.append_description_of(dictionary) \ - .append_text(' is not a mapping object') + mismatch_description.append_description_of(item).append_text(" is not a mapping object") return False - def matches(self, dictionary, mismatch_description=None): + def matches( + self, item: Mapping[K, V], mismatch_description: Optional[Description] = None + ) -> bool: for key, value_matcher in self.value_matchers: - try: - if not key in dictionary: + if key not in item: if mismatch_description: - mismatch_description.append_text('no ') \ - .append_description_of(key) \ - .append_text(' key in ') \ - .append_description_of(dictionary) + mismatch_description.append_text("no ").append_description_of( + key + ).append_text(" key in ").append_description_of(item) return False except TypeError: - return self._not_a_dictionary(dictionary, mismatch_description) + return self._not_a_dictionary(item, mismatch_description) try: - actual_value = dictionary[key] + actual_value = item[key] except TypeError: - return self._not_a_dictionary(dictionary, mismatch_description) + return self._not_a_dictionary(item, mismatch_description) if not value_matcher.matches(actual_value): if mismatch_description: - mismatch_description.append_text('value for ') \ - .append_description_of(key) \ - .append_text(' ') + mismatch_description.append_text("value for ").append_description_of( + key + ).append_text(" ") value_matcher.describe_mismatch(actual_value, mismatch_description) return False return True - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: Mapping[K, V], mismatch_description: Description) -> None: self.matches(item, mismatch_description) - def describe_keyvalue(self, index, value, description): + def describe_keyvalue(self, index: K, value: V, description: Description) -> None: """Describes key-value pair at given index.""" - description.append_description_of(index) \ - .append_text(': ') \ - .append_description_of(value) + description.append_description_of(index).append_text(": ").append_description_of(value) - def describe_to(self, description): - description.append_text('a dictionary containing {') + def describe_to(self, description: Description) -> None: + description.append_text("a dictionary containing {") first = True for key, value in self.value_matchers: if not first: - description.append_text(', ') + description.append_text(", ") self.describe_keyvalue(key, value, description) first = False - description.append_text('}') + description.append_text("}") + + +# Keyword argument form +@overload +def has_entries(**keys_valuematchers: Union[Matcher[V], V]) -> Matcher[Mapping[str, V]]: + ... + + +# Key to matcher dict form +@overload +def has_entries(keys_valuematchers: Mapping[K, Union[Matcher[V], V]]) -> Matcher[Mapping[K, V]]: + ... + + +# Alternating key/matcher form +@overload +def has_entries(*keys_valuematchers: Any) -> Matcher[Mapping[Any, Any]]: + ... def has_entries(*keys_valuematchers, **kv_args): @@ -119,13 +141,17 @@ def has_entries(*keys_valuematchers, **kv_args): for key in base_dict: base_dict[key] = wrap_matcher(base_dict[key]) except AttributeError: - raise ValueError('single-argument calls to has_entries must pass a dict as the argument') + raise ValueError( + "single-argument calls to has_entries must pass a dict as the argument" + ) else: if len(keys_valuematchers) % 2: - raise ValueError('has_entries requires key-value pairs') + raise ValueError("has_entries requires key-value pairs") base_dict = {} for index in range(int(len(keys_valuematchers) / 2)): - base_dict[keys_valuematchers[2 * index]] = wrap_matcher(keys_valuematchers[2 * index + 1]) + base_dict[keys_valuematchers[2 * index]] = wrap_matcher( + keys_valuematchers[2 * index + 1] + ) for key, value in kv_args.items(): base_dict[key] = wrap_matcher(value) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingkey.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingkey.py index ccb51e6396d..90c7cc79ac6 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingkey.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingkey.py @@ -1,30 +1,36 @@ +from typing import Any, Hashable, Mapping, TypeVar, Union + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.hasmethod import hasmethod from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +K = TypeVar("K", bound=Hashable) -class IsDictContainingKey(BaseMatcher): - def __init__(self, key_matcher): +class IsDictContainingKey(BaseMatcher[Mapping[K, Any]]): + def __init__(self, key_matcher: Matcher[K]) -> None: self.key_matcher = key_matcher - def _matches(self, dictionary): - if hasmethod(dictionary, 'keys'): - for key in dictionary.keys(): + def _matches(self, item: Mapping[K, Any]) -> bool: + if hasmethod(item, "keys"): + for key in item.keys(): if self.key_matcher.matches(key): return True return False - def describe_to(self, description): - description.append_text('a dictionary containing key ') \ - .append_description_of(self.key_matcher) + def describe_to(self, description: Description) -> None: + description.append_text("a dictionary containing key ").append_description_of( + self.key_matcher + ) -def has_key(key_match): +def has_key(key_match: Union[K, Matcher[K]]) -> Matcher[Mapping[K, Any]]: """Matches if dictionary contains an entry whose key satisfies a given matcher. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingvalue.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingvalue.py index e5288841b26..ca5b71aa380 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingvalue.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isdict_containingvalue.py @@ -1,30 +1,36 @@ +from typing import Any, Mapping, TypeVar, Union + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.hasmethod import hasmethod from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +V = TypeVar("V") -class IsDictContainingValue(BaseMatcher): - def __init__(self, value_matcher): +class IsDictContainingValue(BaseMatcher[Mapping[Any, V]]): + def __init__(self, value_matcher: Matcher[V]) -> None: self.value_matcher = value_matcher - def _matches(self, dictionary): - if hasmethod(dictionary, 'values'): - for value in dictionary.values(): + def _matches(self, item: Mapping[Any, V]) -> bool: + if hasmethod(item, "values"): + for value in item.values(): if self.value_matcher.matches(value): return True return False - def describe_to(self, description): - description.append_text('a dictionary containing value ') \ - .append_description_of(self.value_matcher) + def describe_to(self, description: Description) -> None: + description.append_text("a dictionary containing value ").append_description_of( + self.value_matcher + ) -def has_value(value): +def has_value(value: Union[V, Matcher[V]]) -> Matcher[Mapping[Any, V]]: """Matches if dictionary contains an entry whose value satisfies a given matcher. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isin.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isin.py index 87962a2474b..e958ea315ca 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isin.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/isin.py @@ -1,24 +1,28 @@ +from typing import Sequence, TypeVar + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +T = TypeVar("T") -class IsIn(BaseMatcher): - def __init__(self, sequence): +class IsIn(BaseMatcher[T]): + def __init__(self, sequence: Sequence[T]) -> None: self.sequence = sequence - def _matches(self, item): + def _matches(self, item: T) -> bool: return item in self.sequence - def describe_to(self, description): - description.append_text('one of ') \ - .append_list('(', ', ', ')', self.sequence) + def describe_to(self, description: Description) -> None: + description.append_text("one of ").append_list("(", ", ", ")", self.sequence) -def is_in(sequence): +def is_in(sequence: Sequence[T]) -> Matcher[T]: """Matches if evaluated object is present in a given sequence. :param sequence: The sequence to search. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containing.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containing.py index 21939b3f3f3..f615dcc7427 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containing.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containing.py @@ -1,56 +1,60 @@ -__author__ = "Jon Reid" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" +from typing import Sequence, TypeVar, Union, cast from hamcrest.core.base_matcher import BaseMatcher from hamcrest.core.core.allof import all_of -from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher + +__author__ = "Jon Reid" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" +T = TypeVar("T") -class IsSequenceContaining(BaseMatcher): - def __init__(self, element_matcher): +class IsSequenceContaining(BaseMatcher[Sequence[T]]): + def __init__(self, element_matcher: Matcher[T]) -> None: self.element_matcher = element_matcher - def _matches(self, sequence): + def _matches(self, item: Sequence[T]) -> bool: try: - for item in sequence: - if self.element_matcher.matches(item): + for element in item: + if self.element_matcher.matches(element): return True - except TypeError: # not a sequence - return False + except TypeError: # not a sequence + pass + return False - def describe_to(self, description): - description.append_text('a sequence containing ') \ - .append_description_of(self.element_matcher) + def describe_to(self, description: Description) -> None: + description.append_text("a sequence containing ").append_description_of( + self.element_matcher + ) # It'd be great to make use of all_of, but we can't be sure we won't # be seeing a one-time sequence here (like a generator); see issue #20 # Instead, we wrap it inside a class that will convert the sequence into # a concrete list and then hand it off to the all_of matcher. -class IsSequenceContainingEvery(BaseMatcher): +class IsSequenceContainingEvery(BaseMatcher[Sequence[T]]): + def __init__(self, *element_matchers: Matcher[T]) -> None: + delegates = [cast(Matcher[Sequence[T]], has_item(e)) for e in element_matchers] + self.matcher: Matcher[Sequence[T]] = all_of(*delegates) - def __init__(self, *element_matchers): - delegates = [has_item(e) for e in element_matchers] - self.matcher = all_of(*delegates) - - def _matches(self, sequence): + def _matches(self, item: Sequence[T]) -> bool: try: - return self.matcher.matches(list(sequence)) + return self.matcher.matches(list(item)) except TypeError: return False - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: Sequence[T], mismatch_description: Description) -> None: self.matcher.describe_mismatch(item, mismatch_description) - def describe_to(self, description): + def describe_to(self, description: Description) -> None: self.matcher.describe_to(description) - -def has_item(match): +def has_item(match: Union[Matcher[T], T]) -> Matcher[Sequence[T]]: """Matches if any element of sequence satisfies a given matcher. :param match: The matcher to satisfy, or an expected value for @@ -68,7 +72,7 @@ def has_item(match): return IsSequenceContaining(wrap_matcher(match)) -def has_items(*items): +def has_items(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]: """Matches if all of the given matchers are satisfied by any elements of the sequence. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginanyorder.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginanyorder.py index 78e2b006fcc..431709c290c 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginanyorder.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginanyorder.py @@ -1,79 +1,85 @@ +from typing import MutableSequence, Optional, Sequence, TypeVar, Union, cast + from hamcrest.core.base_matcher import BaseMatcher -from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +T = TypeVar("T") + class MatchInAnyOrder(object): - def __init__(self, matchers, mismatch_description): - self.matchers = matchers[:] + def __init__( + self, matchers: Sequence[Matcher[T]], mismatch_description: Optional[Description] + ) -> None: + self.matchers = cast(MutableSequence[Matcher[T]], matchers[:]) self.mismatch_description = mismatch_description - def matches(self, item): + def matches(self, item: T) -> bool: return self.isnotsurplus(item) and self.ismatched(item) - def isfinished(self, sequence): + def isfinished(self, item: Sequence[T]) -> bool: if not self.matchers: return True if self.mismatch_description: - self.mismatch_description.append_text('no item matches: ') \ - .append_list('', ', ', '', self.matchers) \ - .append_text(' in ') \ - .append_list('[', ', ', ']', sequence) + self.mismatch_description.append_text("no item matches: ").append_list( + "", ", ", "", self.matchers + ).append_text(" in ").append_list("[", ", ", "]", item) return False - def isnotsurplus(self, item): + def isnotsurplus(self, item: T) -> bool: if not self.matchers: if self.mismatch_description: - self.mismatch_description.append_text('not matched: ') \ - .append_description_of(item) + self.mismatch_description.append_text("not matched: ").append_description_of(item) return False return True - def ismatched(self, item): + def ismatched(self, item: T) -> bool: for index, matcher in enumerate(self.matchers): if matcher.matches(item): del self.matchers[index] return True if self.mismatch_description: - self.mismatch_description.append_text('not matched: ') \ - .append_description_of(item) + self.mismatch_description.append_text("not matched: ").append_description_of(item) return False -class IsSequenceContainingInAnyOrder(BaseMatcher): - - def __init__(self, matchers): +class IsSequenceContainingInAnyOrder(BaseMatcher[Sequence[T]]): + def __init__(self, matchers: Sequence[Matcher[T]]) -> None: self.matchers = matchers - def matches(self, sequence, mismatch_description=None): + def matches( + self, item: Sequence[T], mismatch_description: Optional[Description] = None + ) -> bool: try: - sequence = list(sequence) + sequence = list(item) matchsequence = MatchInAnyOrder(self.matchers, mismatch_description) - for item in sequence: - if not matchsequence.matches(item): + for element in sequence: + if not matchsequence.matches(element): return False return matchsequence.isfinished(sequence) except TypeError: if mismatch_description: - super(IsSequenceContainingInAnyOrder, self) \ - .describe_mismatch(sequence, mismatch_description) + super(IsSequenceContainingInAnyOrder, self).describe_mismatch( + item, mismatch_description + ) return False - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: Sequence[T], mismatch_description: Description) -> None: self.matches(item, mismatch_description) - def describe_to(self, description): - description.append_text('a sequence over ') \ - .append_list('[', ', ', ']', self.matchers) \ - .append_text(' in any order') + def describe_to(self, description: Description) -> None: + description.append_text("a sequence over ").append_list( + "[", ", ", "]", self.matchers + ).append_text(" in any order") -def contains_inanyorder(*items): +def contains_inanyorder(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]: """Matches if sequences's elements, in any order, satisfy a given list of matchers. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginorder.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginorder.py index 7c37b328b61..c7cbda3af07 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginorder.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_containinginorder.py @@ -1,77 +1,84 @@ import warnings +from typing import Optional, Sequence, TypeVar, Union + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.core.base_matcher import BaseMatcher -from hamcrest.core.helpers.hasmethod import hasmethod -from hamcrest.core.helpers.wrap_matcher import wrap_matcher +T = TypeVar("T") class MatchingInOrder(object): - def __init__(self, matchers, mismatch_description): + def __init__( + self, matchers: Sequence[Matcher[T]], mismatch_description: Optional[Description] + ) -> None: self.matchers = matchers self.mismatch_description = mismatch_description self.next_match_index = 0 - def matches(self, item): + def matches(self, item: T) -> bool: return self.isnotsurplus(item) and self.ismatched(item) - def isfinished(self): + def isfinished(self) -> bool: if self.next_match_index < len(self.matchers): if self.mismatch_description: - self.mismatch_description.append_text('No item matched: ') \ - .append_description_of(self.matchers[self.next_match_index]) + self.mismatch_description.append_text("No item matched: ").append_description_of( + self.matchers[self.next_match_index] + ) return False return True - def ismatched(self, item): + def ismatched(self, item: T) -> bool: matcher = self.matchers[self.next_match_index] if not matcher.matches(item): if self.mismatch_description: - self.mismatch_description.append_text('item ' + str(self.next_match_index) + ': ') + self.mismatch_description.append_text("item " + str(self.next_match_index) + ": ") matcher.describe_mismatch(item, self.mismatch_description) return False self.next_match_index += 1 return True - def isnotsurplus(self, item): + def isnotsurplus(self, item: T) -> bool: if len(self.matchers) <= self.next_match_index: if self.mismatch_description: - self.mismatch_description.append_text('Not matched: ') \ - .append_description_of(item) + self.mismatch_description.append_text("Not matched: ").append_description_of(item) return False return True -class IsSequenceContainingInOrder(BaseMatcher): - - def __init__(self, matchers): +class IsSequenceContainingInOrder(BaseMatcher[Sequence[T]]): + def __init__(self, matchers: Sequence[Matcher[T]]) -> None: self.matchers = matchers - def matches(self, sequence, mismatch_description=None): + def matches( + self, item: Sequence[T], mismatch_description: Optional[Description] = None + ) -> bool: try: matchsequence = MatchingInOrder(self.matchers, mismatch_description) - for item in sequence: - if not matchsequence.matches(item): + for element in item: + if not matchsequence.matches(element): return False return matchsequence.isfinished() except TypeError: if mismatch_description: - super(IsSequenceContainingInOrder, self) \ - .describe_mismatch(sequence, mismatch_description) + super(IsSequenceContainingInOrder, self).describe_mismatch( + item, mismatch_description + ) return False - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: Sequence[T], mismatch_description: Description) -> None: self.matches(item, mismatch_description) - def describe_to(self, description): - description.append_text('a sequence containing ') \ - .append_list('[', ', ', ']', self.matchers) + def describe_to(self, description: Description) -> None: + description.append_text("a sequence containing ").append_list("[", ", ", "]", self.matchers) -def contains_exactly(*items): +def contains_exactly(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]: """Matches if sequence's elements satisfy a given list of matchers, in order. :param match1,...: A comma-separated list of matchers. @@ -90,7 +97,7 @@ def contains_exactly(*items): return IsSequenceContainingInOrder(matchers) -def contains(*items): +def contains(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]: """Deprecated - use contains_exactly(*items)""" warnings.warn("deprecated - use contains_exactly(*items)", DeprecationWarning) return contains_exactly(*items) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_onlycontaining.py b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_onlycontaining.py index bd52c10419e..f7819987e19 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_onlycontaining.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/collection/issequence_onlycontaining.py @@ -1,36 +1,41 @@ +from typing import Sequence, TypeVar, Union + from hamcrest.core.base_matcher import BaseMatcher from hamcrest.core.core.anyof import any_of -from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +T = TypeVar("T") -class IsSequenceOnlyContaining(BaseMatcher): - def __init__(self, matcher): +class IsSequenceOnlyContaining(BaseMatcher[Sequence[T]]): + def __init__(self, matcher: Matcher[T]) -> None: self.matcher = matcher - def _matches(self, sequence): + def _matches(self, item: Sequence[T]) -> bool: try: - sequence = list(sequence) + sequence = list(item) if len(sequence) == 0: return False - for item in sequence: - if not self.matcher.matches(item): + for element in sequence: + if not self.matcher.matches(element): return False return True except TypeError: return False - def describe_to(self, description): - description.append_text('a sequence containing items matching ') \ - .append_description_of(self.matcher) + def describe_to(self, description: Description) -> None: + description.append_text("a sequence containing items matching ").append_description_of( + self.matcher + ) -def only_contains(*items): +def only_contains(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]: """Matches if each element of sequence satisfies any of the given matchers. :param match1,...: A comma-separated list of matchers. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/integration/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/library/integration/__init__.py index cc1e1321635..e87d6e1ffc5 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/integration/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/integration/__init__.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import """Utilities for integrating Hamcrest with other libraries.""" from .match_equality import match_equality @@ -6,3 +5,5 @@ from .match_equality import match_equality __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = ["match_equality"] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/integration/match_equality.py b/contrib/python/PyHamcrest/py3/hamcrest/library/integration/match_equality.py index 52da0547605..33494ef2d59 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/integration/match_equality.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/integration/match_equality.py @@ -1,5 +1,8 @@ -from hamcrest.core.string_description import tostring +from typing import Any + from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher +from hamcrest.core.string_description import tostring __author__ = "Chris Rose" __copyright__ = "Copyright 2011 hamcrest.org" @@ -8,21 +11,20 @@ __unittest = True class EqualityWrapper(object): - - def __init__(self, matcher): + def __init__(self, matcher: Matcher) -> None: self.matcher = matcher - def __eq__(self, object): - return self.matcher.matches(object) + def __eq__(self, obj: Any) -> bool: + return self.matcher.matches(obj) - def __str__(self): + def __str__(self) -> str: return repr(self) - def __repr__(self): + def __repr__(self) -> str: return tostring(self.matcher) -def match_equality(matcher): +def match_equality(matcher: Matcher) -> EqualityWrapper: """Wraps a matcher to define equality in terms of satisfying the matcher. ``match_equality`` allows Hamcrest matchers to be used in libraries that diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/number/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/library/number/__init__.py index 5087faf8468..85f4cf69982 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/number/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/number/__init__.py @@ -1,9 +1,21 @@ -from __future__ import absolute_import """Matchers that perform numeric comparisons.""" from .iscloseto import close_to -from .ordering_comparison import greater_than, greater_than_or_equal_to, less_than, less_than_or_equal_to +from .ordering_comparison import ( + greater_than, + greater_than_or_equal_to, + less_than, + less_than_or_equal_to, +) __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [ + "close_to", + "greater_than", + "greater_than_or_equal_to", + "less_than", + "less_than_or_equal_to", +] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/number/iscloseto.py b/contrib/python/PyHamcrest/py3/hamcrest/library/number/iscloseto.py index e401615e356..579eeb8624a 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/number/iscloseto.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/number/iscloseto.py @@ -1,16 +1,21 @@ -import six -from hamcrest.core.base_matcher import BaseMatcher +from decimal import Decimal from math import fabs +from typing import Any, Union, overload + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +Number = Union[float, Decimal] # Argh, https://github.com/python/mypy/issues/3186 -def isnumeric(value): - """Confirm that 'value' can be treated numerically; duck-test accordingly - """ - if isinstance(value, (float, complex) + six.integer_types): + +def isnumeric(value: Any) -> bool: + """Confirm that 'value' can be treated numerically; duck-test accordingly""" + if isinstance(value, (float, complex, int)): return True try: @@ -18,41 +23,52 @@ def isnumeric(value): return True except ArithmeticError: return True - except: + except Exception: return False - return False - -class IsCloseTo(BaseMatcher): - def __init__(self, value, delta): +class IsCloseTo(BaseMatcher[Number]): + def __init__(self, value: Number, delta: Number) -> None: if not isnumeric(value): - raise TypeError('IsCloseTo value must be numeric') + raise TypeError("IsCloseTo value must be numeric") if not isnumeric(delta): - raise TypeError('IsCloseTo delta must be numeric') + raise TypeError("IsCloseTo delta must be numeric") self.value = value self.delta = delta - def _matches(self, item): + def _matches(self, item: Number) -> bool: if not isnumeric(item): return False - return fabs(item - self.value) <= self.delta + return self._diff(item) <= self.delta - def describe_mismatch(self, item, mismatch_description): + def _diff(self, item: Number) -> float: + # TODO - Fails for mixed floats & Decimals + return fabs(item - self.value) # type: ignore + + def describe_mismatch(self, item: Number, mismatch_description: Description) -> None: if not isnumeric(item): super(IsCloseTo, self).describe_mismatch(item, mismatch_description) else: - actual_delta = fabs(item - self.value) - mismatch_description.append_description_of(item) \ - .append_text(' differed by ') \ - .append_description_of(actual_delta) + actual_delta = self._diff(item) + mismatch_description.append_description_of(item).append_text( + " differed by " + ).append_description_of(actual_delta) + + def describe_to(self, description: Description) -> None: + description.append_text("a numeric value within ").append_description_of( + self.delta + ).append_text(" of ").append_description_of(self.value) + + +@overload +def close_to(value: float, delta: float) -> Matcher[float]: + ... + - def describe_to(self, description): - description.append_text('a numeric value within ') \ - .append_description_of(self.delta) \ - .append_text(' of ') \ - .append_description_of(self.value) +@overload +def close_to(value: Decimal, delta: Decimal) -> Matcher[Decimal]: + ... def close_to(value, delta): diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/number/ordering_comparison.py b/contrib/python/PyHamcrest/py3/hamcrest/library/number/ordering_comparison.py index c3c75f425d6..f121caf45f9 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/number/ordering_comparison.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/number/ordering_comparison.py @@ -1,59 +1,69 @@ -from hamcrest.core.base_matcher import BaseMatcher import operator +from typing import Any, Callable + +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class OrderingComparison(BaseMatcher): - - def __init__(self, value, comparison_function, comparison_description): +class OrderingComparison(BaseMatcher[Any]): + def __init__( + self, + value: Any, + comparison_function: Callable[[Any, Any], bool], + comparison_description: str, + ) -> None: self.value = value self.comparison_function = comparison_function self.comparison_description = comparison_description - def _matches(self, item): - return self.comparison_function(item, self.value) + def _matches(self, item: Any) -> bool: + try: + return self.comparison_function(item, self.value) + except TypeError: + return False - def describe_to(self, description): - description.append_text('a value ') \ - .append_text(self.comparison_description) \ - .append_text(' ') \ - .append_description_of(self.value) + def describe_to(self, description: Description) -> None: + description.append_text("a value ").append_text(self.comparison_description).append_text( + " " + ).append_description_of(self.value) -def greater_than(value): +def greater_than(value: Any) -> Matcher[Any]: """Matches if object is greater than a given value. :param value: The value to compare against. """ - return OrderingComparison(value, operator.gt, 'greater than') + return OrderingComparison(value, operator.gt, "greater than") -def greater_than_or_equal_to(value): +def greater_than_or_equal_to(value: Any) -> Matcher[Any]: """Matches if object is greater than or equal to a given value. :param value: The value to compare against. """ - return OrderingComparison(value, operator.ge, 'greater than or equal to') + return OrderingComparison(value, operator.ge, "greater than or equal to") -def less_than(value): +def less_than(value: Any) -> Matcher[Any]: """Matches if object is less than a given value. :param value: The value to compare against. """ - return OrderingComparison(value, operator.lt, 'less than') + return OrderingComparison(value, operator.lt, "less than") -def less_than_or_equal_to(value): +def less_than_or_equal_to(value: Any) -> Matcher[Any]: """Matches if object is less than or equal to a given value. :param value: The value to compare against. """ - return OrderingComparison(value, operator.le, 'less than or equal to') + return OrderingComparison(value, operator.le, "less than or equal to") diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/object/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/library/object/__init__.py index 5ca45566616..e015671d9d8 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/object/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/object/__init__.py @@ -1,10 +1,16 @@ -from __future__ import absolute_import """Matchers that inspect objects and classes.""" from .haslength import has_length -from .hasproperty import has_property, has_properties +from .hasproperty import has_properties, has_property from .hasstring import has_string __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [ + "has_length", + "has_properties", + "has_property", + "has_string", +] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/object/haslength.py b/contrib/python/PyHamcrest/py3/hamcrest/library/object/haslength.py index 3ef0ab5b81e..86d03999d70 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/object/haslength.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/object/haslength.py @@ -1,34 +1,36 @@ +from collections.abc import Sized +from typing import Union + from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.hasmethod import hasmethod from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class HasLength(BaseMatcher): - - def __init__(self, len_matcher): +class HasLength(BaseMatcher[Sized]): + def __init__(self, len_matcher: Matcher[int]) -> None: self.len_matcher = len_matcher - def _matches(self, item): - if not hasmethod(item, '__len__'): + def _matches(self, item: Sized) -> bool: + if not hasmethod(item, "__len__"): return False return self.len_matcher.matches(len(item)) - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: Sized, mismatch_description: Description) -> None: super(HasLength, self).describe_mismatch(item, mismatch_description) - if hasmethod(item, '__len__'): - mismatch_description.append_text(' with length of ') \ - .append_description_of(len(item)) + if hasmethod(item, "__len__"): + mismatch_description.append_text(" with length of ").append_description_of(len(item)) - def describe_to(self, description): - description.append_text('an object with length of ') \ - .append_description_of(self.len_matcher) + def describe_to(self, description: Description) -> None: + description.append_text("an object with length of ").append_description_of(self.len_matcher) -def has_length(match): +def has_length(match: Union[int, Matcher[int]]) -> Matcher[Sized]: """Matches if ``len(item)`` satisfies a given matcher. :param match: The matcher to satisfy, or an expected value for diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasproperty.py b/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasproperty.py index 18f591f1ed6..ea2519f7380 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasproperty.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasproperty.py @@ -1,52 +1,55 @@ +from typing import Any, Mapping, TypeVar, Union, overload + from hamcrest import described_as from hamcrest.core import anything from hamcrest.core.base_matcher import BaseMatcher from hamcrest.core.core.allof import AllOf +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher as wrap_shortcut +from hamcrest.core.matcher import Matcher from hamcrest.core.string_description import StringDescription __author__ = "Chris Rose" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" +V = TypeVar("V") -class IsObjectWithProperty(BaseMatcher): - def __init__(self, property_name, value_matcher): +class IsObjectWithProperty(BaseMatcher[object]): + def __init__(self, property_name: str, value_matcher: Matcher[V]) -> None: self.property_name = property_name self.value_matcher = value_matcher - def _matches(self, o): - if o is None: + def _matches(self, item: object) -> bool: + if item is None: return False - if not hasattr(o, self.property_name): + if not hasattr(item, self.property_name): return False - value = getattr(o, self.property_name) + value = getattr(item, self.property_name) return self.value_matcher.matches(value) - def describe_to(self, description): - description.append_text("an object with a property '") \ - .append_text(self.property_name) \ - .append_text("' matching ") \ - .append_description_of(self.value_matcher) + def describe_to(self, description: Description) -> None: + description.append_text("an object with a property '").append_text( + self.property_name + ).append_text("' matching ").append_description_of(self.value_matcher) - def describe_mismatch(self, item, mismatch_description): + def describe_mismatch(self, item: object, mismatch_description: Description) -> None: if item is None: - mismatch_description.append_text('was None') + mismatch_description.append_text("was None") return if not hasattr(item, self.property_name): - mismatch_description.append_description_of(item) \ - .append_text(' did not have the ') \ - .append_description_of(self.property_name) \ - .append_text(' property') + mismatch_description.append_description_of(item).append_text( + " did not have the " + ).append_description_of(self.property_name).append_text(" property") return - mismatch_description.append_text('property ') \ - .append_description_of(self.property_name) \ - .append_text(' ') + mismatch_description.append_text("property ").append_description_of( + self.property_name + ).append_text(" ") value = getattr(item, self.property_name) self.value_matcher.describe_mismatch(value, mismatch_description) @@ -56,7 +59,7 @@ class IsObjectWithProperty(BaseMatcher): return str(d) -def has_property(name, match=None): +def has_property(name: str, match: Union[None, Matcher[V], V] = None) -> Matcher[object]: """Matches if object has a property with a given name whose value satisfies a given matcher. @@ -89,6 +92,24 @@ def has_property(name, match=None): return IsObjectWithProperty(name, wrap_shortcut(match)) +# Keyword argument form +@overload +def has_properties(**keys_valuematchers: Union[Matcher[V], V]) -> Matcher[Any]: + ... + + +# Name to matcher dict form +@overload +def has_properties(keys_valuematchers: Mapping[str, Union[Matcher[V], V]]) -> Matcher[Any]: + ... + + +# Alternating name/matcher form +@overload +def has_properties(*keys_valuematchers: Any) -> Matcher[Any]: + ... + + def has_properties(*keys_valuematchers, **kv_args): """Matches if an object has properties satisfying all of a dictionary of string property names and corresponding value matchers. @@ -141,31 +162,41 @@ def has_properties(*keys_valuematchers, **kv_args): for key in base_dict: base_dict[key] = wrap_shortcut(base_dict[key]) except AttributeError: - raise ValueError('single-argument calls to has_properties must pass a dict as the argument') + raise ValueError( + "single-argument calls to has_properties must pass a dict as the argument" + ) else: if len(keys_valuematchers) % 2: - raise ValueError('has_properties requires key-value pairs') + raise ValueError("has_properties requires key-value pairs") base_dict = {} for index in range(int(len(keys_valuematchers) / 2)): - base_dict[keys_valuematchers[2 * index]] = wrap_shortcut(keys_valuematchers[2 * index + 1]) + base_dict[keys_valuematchers[2 * index]] = wrap_shortcut( + keys_valuematchers[2 * index + 1] + ) for key, value in kv_args.items(): base_dict[key] = wrap_shortcut(value) if len(base_dict) > 1: - description = StringDescription().append_text('an object with properties ') + description = StringDescription().append_text("an object with properties ") for i, (property_name, property_value_matcher) in enumerate(sorted(base_dict.items())): - description.append_value(property_name).append_text(' matching ').append_description_of( - property_value_matcher) + description.append_description_of(property_name).append_text( + " matching " + ).append_description_of(property_value_matcher) if i < len(base_dict) - 1: - description.append_text(' and ') + description.append_text(" and ") - return described_as(str(description), - AllOf(*[has_property(property_name, property_value_matcher) - for property_name, property_value_matcher - in sorted(base_dict.items())], - describe_all_mismatches=True, - describe_matcher_in_mismatch=False)) + return described_as( + str(description), + AllOf( + *[ + has_property(property_name, property_value_matcher) + for property_name, property_value_matcher in sorted(base_dict.items()) + ], + describe_all_mismatches=True, + describe_matcher_in_mismatch=False, + ), + ) else: property_name, property_value_matcher = base_dict.popitem() return has_property(property_name, property_value_matcher) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasstring.py b/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasstring.py index 8b50547e21c..b03d46615b6 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasstring.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/object/hasstring.py @@ -1,25 +1,25 @@ from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.wrap_matcher import wrap_matcher +from hamcrest.core.matcher import Matcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -class HasString(BaseMatcher): - - def __init__(self, str_matcher): +class HasString(BaseMatcher[object]): + def __init__(self, str_matcher: Matcher[str]) -> None: self.str_matcher = str_matcher - def _matches(self, item): + def _matches(self, item: object) -> bool: return self.str_matcher.matches(str(item)) - def describe_to(self, description): - description.append_text('an object with str ') \ - .append_description_of(self.str_matcher) + def describe_to(self, description: Description) -> None: + description.append_text("an object with str ").append_description_of(self.str_matcher) -def has_string(match): +def has_string(match) -> Matcher[object]: """Matches if ``str(item)`` satisfies a given matcher. :param match: The matcher to satisfy, or an expected value for diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/__init__.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/__init__.py index 39d0e8b3822..19e46c4c88a 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/__init__.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/__init__.py @@ -1,14 +1,23 @@ -from __future__ import absolute_import """Matchers that perform text comparisons.""" from .isequal_ignoring_case import equal_to_ignoring_case from .isequal_ignoring_whitespace import equal_to_ignoring_whitespace from .stringcontains import contains_string +from .stringcontainsinorder import string_contains_in_order from .stringendswith import ends_with -from .stringstartswith import starts_with from .stringmatches import matches_regexp -from .stringcontainsinorder import string_contains_in_order +from .stringstartswith import starts_with __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" + +__all__ = [ + "contains_string", + "ends_with", + "equal_to_ignoring_case", + "equal_to_ignoring_whitespace", + "matches_regexp", + "starts_with", + "string_contains_in_order", +] diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_case.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_case.py index d1ee2d17fc3..c7afb18464f 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_case.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_case.py @@ -1,30 +1,29 @@ +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.core.base_matcher import BaseMatcher - -import six - -class IsEqualIgnoringCase(BaseMatcher): - def __init__(self, string): - if not isinstance(string, six.string_types): - raise TypeError('IsEqualIgnoringCase requires string') +class IsEqualIgnoringCase(BaseMatcher[str]): + def __init__(self, string: str) -> None: + if not isinstance(string, str): + raise TypeError("IsEqualIgnoringCase requires string") self.original_string = string self.lowered_string = string.lower() - def _matches(self, item): - if not isinstance(item, six.string_types): + def _matches(self, item: str) -> bool: + if not isinstance(item, str): return False return self.lowered_string == item.lower() - def describe_to(self, description): - description.append_description_of(self.original_string) \ - .append_text(' ignoring case') + def describe_to(self, description: Description) -> None: + description.append_description_of(self.original_string).append_text(" ignoring case") -def equal_to_ignoring_case(string): +def equal_to_ignoring_case(string: str) -> Matcher[str]: """Matches if object is a string equal to a given string, ignoring case differences. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_whitespace.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_whitespace.py index 86fa997601b..dcb7e853343 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_whitespace.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/isequal_ignoring_whitespace.py @@ -1,18 +1,19 @@ +from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.core.base_matcher import BaseMatcher -import six - -def stripspace(string): - result = '' +def stripspace(string: str) -> str: + result = "" last_was_space = True for character in string: if character.isspace(): if not last_was_space: - result += ' ' + result += " " last_was_space = True else: result += character @@ -20,25 +21,23 @@ def stripspace(string): return result.strip() -class IsEqualIgnoringWhiteSpace(BaseMatcher): - - def __init__(self, string): - if not isinstance(string, six.string_types): - raise TypeError('IsEqualIgnoringWhiteSpace requires string') +class IsEqualIgnoringWhiteSpace(BaseMatcher[str]): + def __init__(self, string) -> None: + if not isinstance(string, str): + raise TypeError("IsEqualIgnoringWhiteSpace requires string") self.original_string = string self.stripped_string = stripspace(string) - def _matches(self, item): - if not isinstance(item, six.string_types): + def _matches(self, item: str) -> bool: + if not isinstance(item, str): return False return self.stripped_string == stripspace(item) - def describe_to(self, description): - description.append_description_of(self.original_string) \ - .append_text(' ignoring whitespace') + def describe_to(self, description: Description) -> None: + description.append_description_of(self.original_string).append_text(" ignoring whitespace") -def equal_to_ignoring_whitespace(string): +def equal_to_ignoring_whitespace(string: str) -> Matcher[str]: """Matches if object is a string equal to a given string, ignoring differences in whitespace. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontains.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontains.py index 58ffd283c66..34df2f6f01d 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontains.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontains.py @@ -1,5 +1,6 @@ -from hamcrest.library.text.substringmatcher import SubstringMatcher from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.matcher import Matcher +from hamcrest.library.text.substringmatcher import SubstringMatcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" @@ -7,20 +8,19 @@ __license__ = "BSD, see License.txt" class StringContains(SubstringMatcher): - - def __init__(self, substring): + def __init__(self, substring) -> None: super(StringContains, self).__init__(substring) - def _matches(self, item): - if not hasmethod(item, 'find'): + def _matches(self, item: str) -> bool: + if not hasmethod(item, "find"): return False return item.find(self.substring) >= 0 def relationship(self): - return 'containing' + return "containing" -def contains_string(substring): +def contains_string(substring: str) -> Matcher[str]: """Matches if object is a string containing a given string. :param string: The string to search for. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontainsinorder.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontainsinorder.py index d5b24ffa40c..73c61fc83ad 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontainsinorder.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringcontainsinorder.py @@ -1,23 +1,22 @@ -__author__ = "Romilly Cocking" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" - from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.matcher import Matcher -import six +__author__ = "Romilly Cocking" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" -class StringContainsInOrder(BaseMatcher): - def __init__(self, *substrings): +class StringContainsInOrder(BaseMatcher[str]): + def __init__(self, *substrings) -> None: for substring in substrings: - if not isinstance(substring, six.string_types): - raise TypeError(self.__class__.__name__ - + ' requires string arguments') + if not isinstance(substring, str): + raise TypeError(self.__class__.__name__ + " requires string arguments") self.substrings = substrings - def _matches(self, item): - if not hasmethod(item, 'find'): + def _matches(self, item: str) -> bool: + if not hasmethod(item, "find"): return False from_index = 0 for substring in self.substrings: @@ -26,12 +25,11 @@ class StringContainsInOrder(BaseMatcher): return False return True - def describe_to(self, description): - description.append_list('a string containing ', ', ', ' in order', - self.substrings) + def describe_to(self, description: Description) -> None: + description.append_list("a string containing ", ", ", " in order", self.substrings) -def string_contains_in_order(*substrings): +def string_contains_in_order(*substrings: str) -> Matcher[str]: """Matches if object is a string containing a given list of substrings in relative order. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringendswith.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringendswith.py index 43f9c3d3021..16bebbdcdde 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringendswith.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringendswith.py @@ -1,5 +1,6 @@ -from hamcrest.library.text.substringmatcher import SubstringMatcher from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.matcher import Matcher +from hamcrest.library.text.substringmatcher import SubstringMatcher __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" @@ -7,20 +8,19 @@ __license__ = "BSD, see License.txt" class StringEndsWith(SubstringMatcher): - - def __init__(self, substring): + def __init__(self, substring) -> None: super(StringEndsWith, self).__init__(substring) - def _matches(self, item): - if not hasmethod(item, 'endswith'): + def _matches(self, item: str) -> bool: + if not hasmethod(item, "endswith"): return False return item.endswith(self.substring) def relationship(self): - return 'ending with' + return "ending with" -def ends_with(string): +def ends_with(string: str) -> Matcher[str]: """Matches if object is a string ending with a given string. :param string: The string to search for. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringmatches.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringmatches.py index 2a16e29729b..e7e8dd4190f 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringmatches.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringmatches.py @@ -1,29 +1,29 @@ -__author__ = "Chris Rose" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" - import re - -import six +from typing import Pattern, Union from hamcrest.core.base_matcher import BaseMatcher -from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.description import Description +from hamcrest.core.matcher import Matcher + +__author__ = "Chris Rose" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" -class StringMatchesPattern(BaseMatcher): - def __init__(self, pattern): +class StringMatchesPattern(BaseMatcher[str]): + def __init__(self, pattern) -> None: self.pattern = pattern - def describe_to(self, description): - description.append_text("a string matching '") \ - .append_text(self.pattern.pattern) \ - .append_text("'") + def describe_to(self, description: Description) -> None: + description.append_text("a string matching '").append_text( + self.pattern.pattern + ).append_text("'") - def _matches(self, item): + def _matches(self, item: str) -> bool: return self.pattern.search(item) is not None -def matches_regexp(pattern): +def matches_regexp(pattern: Union[str, Pattern[str]]) -> Matcher[str]: """Matches if object is a string containing a match for a given regular expression. @@ -34,7 +34,7 @@ def matches_regexp(pattern): evaluated object. """ - if isinstance(pattern, six.string_types): + if isinstance(pattern, str): pattern = re.compile(pattern) return StringMatchesPattern(pattern) diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringstartswith.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringstartswith.py index a0af49c9c2a..c3cc7eef408 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringstartswith.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/stringstartswith.py @@ -1,26 +1,26 @@ +from hamcrest.core.helpers.hasmethod import hasmethod +from hamcrest.core.matcher import Matcher +from hamcrest.library.text.substringmatcher import SubstringMatcher + __author__ = "Jon Reid" __copyright__ = "Copyright 2011 hamcrest.org" __license__ = "BSD, see License.txt" -from hamcrest.library.text.substringmatcher import SubstringMatcher -from hamcrest.core.helpers.hasmethod import hasmethod - class StringStartsWith(SubstringMatcher): - - def __init__(self, substring): + def __init__(self, substring) -> None: super(StringStartsWith, self).__init__(substring) - def _matches(self, item): - if not hasmethod(item, 'startswith'): + def _matches(self, item: str) -> bool: + if not hasmethod(item, "startswith"): return False return item.startswith(self.substring) def relationship(self): - return 'starting with' + return "starting with" -def starts_with(substring): +def starts_with(substring: str) -> Matcher[str]: """Matches if object is a string starting with a given string. :param string: The string to search for. diff --git a/contrib/python/PyHamcrest/py3/hamcrest/library/text/substringmatcher.py b/contrib/python/PyHamcrest/py3/hamcrest/library/text/substringmatcher.py index 63ea359a51c..ec7874c5f07 100644 --- a/contrib/python/PyHamcrest/py3/hamcrest/library/text/substringmatcher.py +++ b/contrib/python/PyHamcrest/py3/hamcrest/library/text/substringmatcher.py @@ -1,20 +1,24 @@ -__author__ = "Jon Reid" -__copyright__ = "Copyright 2011 hamcrest.org" -__license__ = "BSD, see License.txt" +from abc import ABCMeta, abstractmethod from hamcrest.core.base_matcher import BaseMatcher +from hamcrest.core.description import Description -import six +__author__ = "Jon Reid" +__copyright__ = "Copyright 2011 hamcrest.org" +__license__ = "BSD, see License.txt" -class SubstringMatcher(BaseMatcher): - def __init__(self, substring): - if not isinstance(substring, six.string_types): - raise TypeError(self.__class__.__name__ + ' requires string') +class SubstringMatcher(BaseMatcher[str], metaclass=ABCMeta): + def __init__(self, substring) -> None: + if not isinstance(substring, str): + raise TypeError(self.__class__.__name__ + " requires string") self.substring = substring - def describe_to(self, description): - description.append_text('a string ') \ - .append_text(self.relationship()) \ - .append_text(' ') \ - .append_description_of(self.substring) + def describe_to(self, description: Description) -> None: + description.append_text("a string ").append_text(self.relationship()).append_text( + " " + ).append_description_of(self.substring) + + @abstractmethod + def relationship(self): + ... diff --git a/contrib/python/PyHamcrest/py3/hamcrest/py.typed b/contrib/python/PyHamcrest/py3/hamcrest/py.typed new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/contrib/python/PyHamcrest/py3/hamcrest/py.typed |
