From d413c030a0ab9c26ce979f8d953362405d902980 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 11:12:38 -0700 Subject: [PATCH 01/10] begin eliminating hypothesis --- .gitignore | 1 - mypy.ini | 5 ---- requirements/tox-tests.txt | 1 - src/klein/test/__init__.py | 12 ---------- src/klein/test/test_headers.py | 11 --------- src/klein/test/test_message.py | 3 --- src/klein/test/test_plating.py | 33 --------------------------- src/klein/test/test_request_compat.py | 3 --- tox.ini | 1 - 9 files changed, 70 deletions(-) diff --git a/.gitignore b/.gitignore index 9f48daf88..4702ad0a2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ *~ .DS_Store /.eggs -/.hypothesis/ /.tox/ /apidocs/ /build/ diff --git a/mypy.ini b/mypy.ini index 1d53011e8..94e2a3ff7 100644 --- a/mypy.ini +++ b/mypy.ini @@ -63,11 +63,6 @@ ignore_missing_imports = True [mypy-treq.*] ignore_missing_imports = True -[mypy-hypothesis] -ignore_missing_imports = True -[mypy-hypothesis.*] -ignore_missing_imports = True - [mypy-idna] ignore_missing_imports = True diff --git a/requirements/tox-tests.txt b/requirements/tox-tests.txt index 5dbccbafe..d17b21971 100644 --- a/requirements/tox-tests.txt +++ b/requirements/tox-tests.txt @@ -1,3 +1,2 @@ treq==22.2.0 -hypothesis==6.48.2 idna==3.3 diff --git a/src/klein/test/__init__.py b/src/klein/test/__init__.py index 537416ef2..e78e34948 100644 --- a/src/klein/test/__init__.py +++ b/src/klein/test/__init__.py @@ -4,15 +4,3 @@ """ Tests for L{klein}. """ - -from hypothesis import HealthCheck, settings - - -settings.register_profile( - "patience", - settings( - deadline=None, - suppress_health_check=[HealthCheck.too_slow], - ), -) -settings.load_profile("patience") diff --git a/src/klein/test/test_headers.py b/src/klein/test/test_headers.py index bb236279d..c7c9133e3 100644 --- a/src/klein/test/test_headers.py +++ b/src/klein/test/test_headers.py @@ -20,17 +20,6 @@ cast, ) -from hypothesis import given -from hypothesis.strategies import ( - binary, - characters, - composite, - iterables, - lists, - text, - tuples, -) - from .._headers import ( HEADER_NAME_ENCODING, HEADER_VALUE_ENCODING, diff --git a/src/klein/test/test_message.py b/src/klein/test/test_message.py index f07dfa4da..985f6f84d 100644 --- a/src/klein/test/test_message.py +++ b/src/klein/test/test_message.py @@ -8,9 +8,6 @@ from abc import ABC, abstractmethod from typing import cast -from hypothesis import given -from hypothesis.strategies import binary - from twisted.internet.defer import ensureDeferred from .._imessage import IHTTPMessage diff --git a/src/klein/test/test_plating.py b/src/klein/test/test_plating.py index c11f2fc2b..62d6470b3 100644 --- a/src/klein/test/test_plating.py +++ b/src/klein/test/test_plating.py @@ -9,8 +9,6 @@ from typing import Any import attr -from hypothesis import given, settings -from hypothesis import strategies as st from twisted.internet.defer import Deferred, succeed from twisted.trial.unittest import SynchronousTestCase @@ -128,37 +126,6 @@ def resolve(self): ) -def jsonComposites(children): - """ - Creates a Hypothesis strategy that constructs composite - JSON-serializable objects (e.g., lists). - - @param children: A strategy from which each composite object's - children will be drawn. - - @return: The composite objects strategy. - """ - return ( - st.lists(children) - | st.dictionaries(st.text(printable), children) - | st.tuples(children) - ) - - -jsonObjects = st.recursive(jsonAtoms, jsonComposites, max_leaves=200) - - -@atexit.register -def invalidateJsonStrategy() -> None: - """ - hypothesis RecursiveStrategy hangs on to a threadlocal object which causes - disttrial to hang for some reason. - - Possibly related to U{this }. - """ - jsonObjects.limited_base._threadlocal = None - - def transformJSONObject(jsonObject, transformer): """ Recursively apply a transforming function to a JSON serializable diff --git a/src/klein/test/test_request_compat.py b/src/klein/test/test_request_compat.py index 5096bbc61..4fcb0d291 100644 --- a/src/klein/test/test_request_compat.py +++ b/src/klein/test/test_request_compat.py @@ -19,9 +19,6 @@ ) from hyperlink import DecodedURL, EncodedURL -from hyperlink.hypothesis import decoded_urls -from hypothesis import given -from hypothesis.strategies import binary, text from twisted.internet.defer import ensureDeferred from twisted.web.iweb import IRequest diff --git a/tox.ini b/tox.ini index 389ea6526..441b87b43 100644 --- a/tox.ini +++ b/tox.ini @@ -67,7 +67,6 @@ setenv = coverage: COVERAGE_PROCESS_START={toxinidir}/.coveragerc TRIAL_JOBS={env:TRIAL_JOBS:--jobs=2} - HYPOTHESIS_STORAGE_DIRECTORY={toxworkdir}/hypothesis commands = # Run trial without coverage From f6a9a3bfec6c90ac0d0a49763ab648a25d2d3dc8 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 12:51:52 -0700 Subject: [PATCH 02/10] checkpoint --- src/klein/test/not_hypothesis.py | 85 +++++++++++++++++++++++++++ src/klein/test/test_headers.py | 62 ++++--------------- src/klein/test/test_message.py | 1 + src/klein/test/test_plating.py | 14 +---- src/klein/test/test_request_compat.py | 1 + 5 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 src/klein/test/not_hypothesis.py diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py new file mode 100644 index 000000000..bfefeba00 --- /dev/null +++ b/src/klein/test/not_hypothesis.py @@ -0,0 +1,85 @@ +from functools import wraps +from typing import Callable, Iterable, Tuple, TypeVar + + +T = TypeVar("T") +S = TypeVar("S") + + +def given( + parameters: Callable[[], Iterable[T]] +) -> Callable[[Callable[[S, T], None]], Callable[[S], None]]: + def decorator(testMethod: Callable[[S, T], None]) -> Callable[[S], None]: + @wraps(testMethod) + def realTestMethod(self: S) -> None: + for parameter in parameters(): + testMethod(self, parameter) + + return realTestMethod + + return decorator + + +def binary() -> Callable[[], Iterable[bytes]]: + """ + Generate some binary data. + """ + + def params() -> Iterable[bytes]: + return [b"data", b"data data data", b"\x00" * 50] + + return params + + +def ascii_text(min_size: int = 0) -> Callable[[], Iterable[str]]: + """ + Generate some ASCII strs. + """ + + def params() -> Iterable[str]: + yield from [ + "latin1-text", + "some more latin1 text", + "hére is latin1 text", + ] + if not min_size: + yield "" + + return params + + +def latin1_text(min_size: int = 0) -> Callable[[], Iterable[str]]: + """ + Generate some strings encodable as latin1 + """ + + def params() -> Iterable[str]: + yield from [ + "latin1-text", + "some more latin1 text", + "hére is latin1 text", + ] + if not min_size: + yield "" + + return params + + +def text(min_size: int = 0) -> Callable[[], Iterable[str]]: + """ + Generate some text. + """ + + def params() -> Iterable[str]: + yield from latin1_text(min_size)() + yield "\N{SNOWMAN}" + + return params + + +def textHeaderPairs() -> Callable[[], Iterable[Iterable[Tuple[str, str]]]]: + """ """ + + +def bytesHeaderPairs() -> Callable[[], Iterable[Iterable[Tuple[str, bytes]]]]: + """ """ diff --git a/src/klein/test/test_headers.py b/src/klein/test/test_headers.py index c7c9133e3..002281a4e 100644 --- a/src/klein/test/test_headers.py +++ b/src/klein/test/test_headers.py @@ -7,7 +7,6 @@ from abc import ABC, abstractmethod from collections import defaultdict -from string import ascii_letters from typing import ( AnyStr, Callable, @@ -38,6 +37,14 @@ normalizeRawHeadersFrozen, ) from ._trial import TestCase +from .not_hypothesis import ( + binary, + bytesHeaderPairs, + given, + latin1_text, + text, + textHeaderPairs, +) __all__ = () @@ -47,55 +54,6 @@ DrawCallable = Callable[[Callable[..., T]], T] -@composite -def ascii_text( - draw: DrawCallable, - min_size: Optional[int] = 0, - max_size: Optional[int] = None, -) -> str: # pragma: no cover - """ - A strategy which generates ASCII-encodable text. - - @param min_size: The minimum number of characters in the text. - C{None} is treated as C{0}. - - @param max_size: The maximum number of characters in the text. - Use C{None} for an unbounded size. - """ - return cast( - str, - draw( - text(min_size=min_size, max_size=max_size, alphabet=ascii_letters) - ), - ) - - -@composite # pragma: no cover -def latin1_text( - draw: DrawCallable, - min_size: Optional[int] = 0, - max_size: Optional[int] = None, -) -> str: - """ - A strategy which generates ISO-8859-1-encodable text. - - @param min_size: The minimum number of characters in the text. - C{None} is treated as C{0}. - - @param max_size: The maximum number of characters in the text. - Use C{None} for an unbounded size. - """ - return "".join( - draw( - lists( - characters(max_codepoint=255), - min_size=min_size, - max_size=max_size, - ) - ) - ) - - def encodeName(name: str) -> Optional[bytes]: return name.encode(HEADER_NAME_ENCODING) @@ -293,7 +251,7 @@ def headerNormalize(self, value: str) -> str: """ return value - @given(iterables(tuples(ascii_text(min_size=1), latin1_text()))) + @given(textHeaderPairs()) def test_getTextName(self, textPairs: Iterable[Tuple[str, str]]) -> None: """ C{getValues} returns an iterable of L{str} values for @@ -322,7 +280,7 @@ def test_getTextName(self, textPairs: Iterable[Tuple[str, str]]) -> None: f"header name: {name!r}", ) - @given(iterables(tuples(ascii_text(min_size=1), binary()))) + @given(bytesHeaderPairs()) def test_getTextNameBinaryValues( self, pairs: Iterable[Tuple[str, bytes]] ) -> None: diff --git a/src/klein/test/test_message.py b/src/klein/test/test_message.py index 985f6f84d..fd8d0c355 100644 --- a/src/klein/test/test_message.py +++ b/src/klein/test/test_message.py @@ -13,6 +13,7 @@ from .._imessage import IHTTPMessage from .._message import FountAlreadyAccessedError, bytesToFount, fountToBytes from ._trial import TestCase +from .not_hypothesis import binary, given __all__ = () diff --git a/src/klein/test/test_plating.py b/src/klein/test/test_plating.py index 62d6470b3..e0f292289 100644 --- a/src/klein/test/test_plating.py +++ b/src/klein/test/test_plating.py @@ -3,9 +3,7 @@ """ -import atexit import json -from string import printable from typing import Any import attr @@ -18,6 +16,7 @@ from .. import Klein, Plating from .._plating import ATOM_TYPES, PlatedElement, resolveDeferredObjects +from .not_hypothesis import given, jsonObjects from .test_resource import MockRequest, _render @@ -117,15 +116,6 @@ def resolve(self): self.deferred.callback(self.value) -jsonAtoms = ( - st.none() - | st.booleans() - | st.integers() - | st.floats(allow_nan=False) - | st.text(printable) -) - - def transformJSONObject(jsonObject, transformer): """ Recursively apply a transforming function to a JSON serializable @@ -219,7 +209,6 @@ class ResolveDeferredObjectsTests(SynchronousTestCase): Tests for L{resolve_deferred_objects}. """ - @settings(max_examples=500) @given( jsonObject=jsonObjects, data=st.data(), @@ -261,7 +250,6 @@ def test_elementSerialized(self, jsonObject, data): A L{PlatedElement} within a JSON serializable object replaced by its JSON representation. """ - choose = st.booleans() def injectPlatingElements(value): if data.draw(choose) and isinstance(value, dict): diff --git a/src/klein/test/test_request_compat.py b/src/klein/test/test_request_compat.py index 4fcb0d291..816b59ea8 100644 --- a/src/klein/test/test_request_compat.py +++ b/src/klein/test/test_request_compat.py @@ -28,6 +28,7 @@ from .._request import IHTTPRequest from .._request_compat import HTTPRequestWrappingIRequest from ._trial import TestCase +from .not_hypothesis import binary, given from .test_resource import MockRequest From d3276bc24bffe75d47177ce5a9894c41e483efbf Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 13:23:50 -0700 Subject: [PATCH 03/10] and that's a wrap --- src/klein/test/not_hypothesis.py | 56 ++++++++++++++++++++++++++++---- src/klein/test/test_plating.py | 19 +++++------ 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index bfefeba00..7a6cf7f1e 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -1,4 +1,5 @@ from functools import wraps +from itertools import product from typing import Callable, Iterable, Tuple, TypeVar @@ -7,13 +8,30 @@ def given( - parameters: Callable[[], Iterable[T]] -) -> Callable[[Callable[[S, T], None]], Callable[[S], None]]: - def decorator(testMethod: Callable[[S, T], None]) -> Callable[[S], None]: + *args: Callable[[], Iterable[T]], + **kwargs: Callable[[], Iterable[T]], +) -> Callable[[Callable[..., None]], Callable[..., None]]: + def decorator(testMethod: Callable[..., None]) -> Callable[..., None]: @wraps(testMethod) def realTestMethod(self: S) -> None: - for parameter in parameters(): - testMethod(self, parameter) + everyPossibleArgs = product( + *[eachFactory() for eachFactory in args] + ) + everyPossibleKwargs = product( + *[ + [(name, eachValue) for eachValue in eachFactory()] + for (name, eachFactory) in kwargs.items() + ] + ) + everyPossibleSignature = product( + everyPossibleArgs, everyPossibleKwargs + ) + # not quite the _full_ cartesian product but the whole point is + # that we're making a feeble attempt at this rather than bringing + # in hypothesis. + for (computedArgs, computedPairs) in everyPossibleSignature: + computedKwargs = dict(computedPairs) + testMethod(self, *computedArgs, **computedKwargs) return realTestMethod @@ -65,7 +83,9 @@ def params() -> Iterable[str]: return params -def text(min_size: int = 0) -> Callable[[], Iterable[str]]: +def text( + min_size: int = 0, alphabet: str = "ignored" +) -> Callable[[], Iterable[str]]: """ Generate some text. """ @@ -83,3 +103,27 @@ def textHeaderPairs() -> Callable[[], Iterable[Iterable[Tuple[str, str]]]]: def bytesHeaderPairs() -> Callable[[], Iterable[Iterable[Tuple[str, bytes]]]]: """ """ + + +def booleans() -> Callable[[], Iterable[bool]]: + def parameters() -> Iterable[bool]: + yield True + yield False + + return parameters + + +def jsonObjects() -> Callable[[], Iterable[object]]: + def parameters() -> Iterable[object]: + yield {} + yield {"hello": "world"} + yield {"here is": {"some": "nesting"}} + yield { + "and": "multiple", + "keys": { + "with": "nesting", + "and": 1234, + "numbers": ["with", "lists", "too"], + }, + } + return parameters diff --git a/src/klein/test/test_plating.py b/src/klein/test/test_plating.py index e0f292289..40bef2aaa 100644 --- a/src/klein/test/test_plating.py +++ b/src/klein/test/test_plating.py @@ -16,7 +16,7 @@ from .. import Klein, Plating from .._plating import ATOM_TYPES, PlatedElement, resolveDeferredObjects -from .not_hypothesis import given, jsonObjects +from .not_hypothesis import given, jsonObjects, booleans from .test_resource import MockRequest, _render @@ -210,20 +210,19 @@ class ResolveDeferredObjectsTests(SynchronousTestCase): """ @given( - jsonObject=jsonObjects, - data=st.data(), + jsonObject=jsonObjects(), + shouldWrapDeferred=booleans(), ) - def test_resolveObjects(self, jsonObject, data): + def test_resolveObjects(self, jsonObject: object, shouldWrapDeferred: bool) -> None: """ A JSON serializable object that may contain L{Deferred}s or a L{Deferred} that resolves to a JSON serializable object resolves to an object that contains no L{Deferred}s. """ deferredValues = [] - choose = st.booleans() def maybeWrapInDeferred(value): - if data.draw(choose): + if shouldWrapDeferred: deferredValues.append(DeferredValue(value)) return deferredValues[-1].deferred else: @@ -242,17 +241,17 @@ def maybeWrapInDeferred(value): self.assertEqual(self.successResultOf(resolved), jsonObject) @given( - jsonObject=jsonObjects, - data=st.data(), + jsonObject=jsonObjects(), + shouldInjectElements=booleans(), ) - def test_elementSerialized(self, jsonObject, data): + def test_elementSerialized(self, jsonObject: object, shouldInjectElements: bool) -> None: """ A L{PlatedElement} within a JSON serializable object replaced by its JSON representation. """ def injectPlatingElements(value): - if data.draw(choose) and isinstance(value, dict): + if shouldInjectElements and isinstance(value, dict): return PlatedElement( slot_data=value, preloaded=tags.html(), From bb90e2561627c60a01afb2d0ff55a77c2303f075 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 13:31:26 -0700 Subject: [PATCH 04/10] almost there --- src/klein/test/not_hypothesis.py | 16 ++++++++++++++++ src/klein/test/test_request_compat.py | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index 7a6cf7f1e..5358327de 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -2,6 +2,8 @@ from itertools import product from typing import Callable, Iterable, Tuple, TypeVar +from hyperlink import DecodedURL, parse as parseURL + T = TypeVar("T") S = TypeVar("S") @@ -126,4 +128,18 @@ def parameters() -> Iterable[object]: "numbers": ["with", "lists", "too"], }, } + + return parameters + + +def decoded_urls() -> Callable[[], Iterable[DecodedURL]]: + def parameters() -> Iterable[DecodedURL]: + yield DecodedURL.from_text("https://example.com/") + yield DecodedURL.from_text("https://sub.example.com/?query=params") + yield DecodedURL.from_text( + "https://user:pass@example.com/?query=params" + ) + yield DecodedURL.from_text( + "https://user:pass@example.com/?query=params#fragment-too" + ) return parameters diff --git a/src/klein/test/test_request_compat.py b/src/klein/test/test_request_compat.py index 816b59ea8..3e9845083 100644 --- a/src/klein/test/test_request_compat.py +++ b/src/klein/test/test_request_compat.py @@ -28,7 +28,7 @@ from .._request import IHTTPRequest from .._request_compat import HTTPRequestWrappingIRequest from ._trial import TestCase -from .not_hypothesis import binary, given +from .not_hypothesis import binary, given, text, decoded_urls from .test_resource import MockRequest From 8a9a9927eaa552cbf1c270f3544a7d10cc8884a2 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 13:55:59 -0700 Subject: [PATCH 05/10] explanation, formatting --- src/klein/test/not_hypothesis.py | 56 ++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index 5358327de..428b65c6f 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -1,6 +1,16 @@ +""" +We have had a history of U{bad +experiences} with Hypothesis in +Klein, and maybe it's not actually a good application of this tool at all. As +such we have removed it, at least for now. This module presents a vaguely +Hypothesis-like stub, to keep the structure of our tests in a +Hypothesis-friendly shape, in case we want to put it back. +""" + from functools import wraps from itertools import product -from typing import Callable, Iterable, Tuple, TypeVar +from string import ascii_uppercase +from typing import Callable, Iterable, Optional, Tuple, TypeVar from hyperlink import DecodedURL, parse as parseURL @@ -58,9 +68,8 @@ def ascii_text(min_size: int = 0) -> Callable[[], Iterable[str]]: def params() -> Iterable[str]: yield from [ - "latin1-text", - "some more latin1 text", - "hére is latin1 text", + "ascii-text", + "some more ascii text", ] if not min_size: yield "" @@ -86,13 +95,16 @@ def params() -> Iterable[str]: def text( - min_size: int = 0, alphabet: str = "ignored" + min_size: int = 0, alphabet: Optional[str] = None ) -> Callable[[], Iterable[str]]: """ Generate some text. """ def params() -> Iterable[str]: + if alphabet == ascii_uppercase: + yield from ascii_text()() + return yield from latin1_text(min_size)() yield "\N{SNOWMAN}" @@ -100,11 +112,25 @@ def params() -> Iterable[str]: def textHeaderPairs() -> Callable[[], Iterable[Iterable[Tuple[str, str]]]]: - """ """ + """ + Generate some pairs of headers with text values. + """ + + def params() -> Iterable[Iterable[Tuple[str, str]]]: + return [[], [("text", "header")]] + + return params def bytesHeaderPairs() -> Callable[[], Iterable[Iterable[Tuple[str, bytes]]]]: - """ """ + """ + Generate some pairs of headers with bytes values. + """ + + def params() -> Iterable[Iterable[Tuple[str, bytes]]]: + return [[], [("bytes", b"header")]] + + return params def booleans() -> Callable[[], Iterable[bool]]: @@ -133,13 +159,15 @@ def parameters() -> Iterable[object]: def decoded_urls() -> Callable[[], Iterable[DecodedURL]]: + """ + Generate a few URLs U{with only path and domain names + } kind of like + Hyperlink's own hypothesis strategy. + """ + def parameters() -> Iterable[DecodedURL]: yield DecodedURL.from_text("https://example.com/") - yield DecodedURL.from_text("https://sub.example.com/?query=params") - yield DecodedURL.from_text( - "https://user:pass@example.com/?query=params" - ) - yield DecodedURL.from_text( - "https://user:pass@example.com/?query=params#fragment-too" - ) + yield DecodedURL.from_text("https://example.com/é") + yield DecodedURL.from_text("https://súbdomain.example.com/ascii/path/") + return parameters From f3ed65b8ba13a5fcbb5898c1451c5133744e27f5 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 13:57:06 -0700 Subject: [PATCH 06/10] thanks linters --- src/klein/test/not_hypothesis.py | 2 +- src/klein/test/test_plating.py | 10 +++++++--- src/klein/test/test_request_compat.py | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index 428b65c6f..0559c711a 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -12,7 +12,7 @@ from string import ascii_uppercase from typing import Callable, Iterable, Optional, Tuple, TypeVar -from hyperlink import DecodedURL, parse as parseURL +from hyperlink import DecodedURL T = TypeVar("T") diff --git a/src/klein/test/test_plating.py b/src/klein/test/test_plating.py index 40bef2aaa..5cf795bbf 100644 --- a/src/klein/test/test_plating.py +++ b/src/klein/test/test_plating.py @@ -16,7 +16,7 @@ from .. import Klein, Plating from .._plating import ATOM_TYPES, PlatedElement, resolveDeferredObjects -from .not_hypothesis import given, jsonObjects, booleans +from .not_hypothesis import booleans, given, jsonObjects from .test_resource import MockRequest, _render @@ -213,7 +213,9 @@ class ResolveDeferredObjectsTests(SynchronousTestCase): jsonObject=jsonObjects(), shouldWrapDeferred=booleans(), ) - def test_resolveObjects(self, jsonObject: object, shouldWrapDeferred: bool) -> None: + def test_resolveObjects( + self, jsonObject: object, shouldWrapDeferred: bool + ) -> None: """ A JSON serializable object that may contain L{Deferred}s or a L{Deferred} that resolves to a JSON serializable object @@ -244,7 +246,9 @@ def maybeWrapInDeferred(value): jsonObject=jsonObjects(), shouldInjectElements=booleans(), ) - def test_elementSerialized(self, jsonObject: object, shouldInjectElements: bool) -> None: + def test_elementSerialized( + self, jsonObject: object, shouldInjectElements: bool + ) -> None: """ A L{PlatedElement} within a JSON serializable object replaced by its JSON representation. diff --git a/src/klein/test/test_request_compat.py b/src/klein/test/test_request_compat.py index 3e9845083..3a40d2c5b 100644 --- a/src/klein/test/test_request_compat.py +++ b/src/klein/test/test_request_compat.py @@ -28,7 +28,7 @@ from .._request import IHTTPRequest from .._request_compat import HTTPRequestWrappingIRequest from ._trial import TestCase -from .not_hypothesis import binary, given, text, decoded_urls +from .not_hypothesis import binary, decoded_urls, given, text from .test_resource import MockRequest From 3cff37926710d6b6bd82d27a23f55cd4eeb4c193 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 14:14:23 -0700 Subject: [PATCH 07/10] don't need this parameter yet, so get rid of uncovered line --- src/klein/test/not_hypothesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index 0559c711a..844a44441 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -61,7 +61,7 @@ def params() -> Iterable[bytes]: return params -def ascii_text(min_size: int = 0) -> Callable[[], Iterable[str]]: +def ascii_text(min_size: int) -> Callable[[], Iterable[str]]: """ Generate some ASCII strs. """ From 9110cd232a37559d9d5a24ea63f287e60792d30e Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 14:17:17 -0700 Subject: [PATCH 08/10] min_size parameter not used, let's skip the coverage problem --- src/klein/test/not_hypothesis.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index 844a44441..5d7d261cb 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -71,8 +71,7 @@ def params() -> Iterable[str]: "ascii-text", "some more ascii text", ] - if not min_size: - yield "" + assert min_size, "nothing needs 0-length strings right now" return params @@ -103,7 +102,7 @@ def text( def params() -> Iterable[str]: if alphabet == ascii_uppercase: - yield from ascii_text()() + yield from ascii_text(min_size)() return yield from latin1_text(min_size)() yield "\N{SNOWMAN}" From c555bfb164d0f1328735f1cb1a9e02f3f256c192 Mon Sep 17 00:00:00 2001 From: Glyph Date: Tue, 2 May 2023 14:22:20 -0700 Subject: [PATCH 09/10] address some coverage gaps --- src/klein/test/not_hypothesis.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index 5d7d261cb..a3536b72c 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -56,7 +56,7 @@ def binary() -> Callable[[], Iterable[bytes]]: """ def params() -> Iterable[bytes]: - return [b"data", b"data data data", b"\x00" * 50] + return [b"data", b"data data data", b"\x00" * 50, b""] return params @@ -151,6 +151,7 @@ def parameters() -> Iterable[object]: "with": "nesting", "and": 1234, "numbers": ["with", "lists", "too"], + "also": ("tuples", "can", "serialize"), }, } @@ -166,6 +167,8 @@ def decoded_urls() -> Callable[[], Iterable[DecodedURL]]: def parameters() -> Iterable[DecodedURL]: yield DecodedURL.from_text("https://example.com/") + yield DecodedURL.from_text("https://example.com") + yield DecodedURL.from_text("http://example.com/") yield DecodedURL.from_text("https://example.com/é") yield DecodedURL.from_text("https://súbdomain.example.com/ascii/path/") From 87c08f6b4aa143247a090594651d68027774d050 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 22:08:00 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/klein/test/not_hypothesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/klein/test/not_hypothesis.py b/src/klein/test/not_hypothesis.py index a3536b72c..da8f6142e 100644 --- a/src/klein/test/not_hypothesis.py +++ b/src/klein/test/not_hypothesis.py @@ -41,7 +41,7 @@ def realTestMethod(self: S) -> None: # not quite the _full_ cartesian product but the whole point is # that we're making a feeble attempt at this rather than bringing # in hypothesis. - for (computedArgs, computedPairs) in everyPossibleSignature: + for computedArgs, computedPairs in everyPossibleSignature: computedKwargs = dict(computedPairs) testMethod(self, *computedArgs, **computedKwargs)