Skip to content

Commit

Permalink
Merge pull request #3966 from tybug/cache-extract-lambda-source
Browse files Browse the repository at this point in the history
cache extract_lambda_source
  • Loading branch information
Zac-HD authored May 3, 2024
2 parents 8005910 + dfb720e commit 0a17774
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 11 deletions.
3 changes: 3 additions & 0 deletions hypothesis-python/RELEASE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
RELEASE_TYPE: patch

This patch fixes a significant slowdown when using the :func:`~hypothesis.stateful.precondition` decorator in some cases, due to expensive repr formatting internally (:issue:`3963`).
3 changes: 0 additions & 3 deletions hypothesis-python/src/RELEASE.rst

This file was deleted.

19 changes: 16 additions & 3 deletions hypothesis-python/src/hypothesis/internal/reflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@
from random import _inst as global_random_instance
from tokenize import COMMENT, detect_encoding, generate_tokens, untokenize
from types import ModuleType
from typing import TYPE_CHECKING, Any, Callable
from typing import TYPE_CHECKING, Any, Callable, MutableMapping
from unittest.mock import _patch as PatchType
from weakref import WeakKeyDictionary

from hypothesis.errors import HypothesisWarning
from hypothesis.internal.compat import PYPY, is_typed_named_tuple
Expand All @@ -39,6 +40,7 @@
from hypothesis.strategies._internal.strategies import T

READTHEDOCS = os.environ.get("READTHEDOCS", None) == "True"
LAMBDA_SOURCE_CACHE: MutableMapping[Callable, str] = WeakKeyDictionary()


def is_mock(obj):
Expand Down Expand Up @@ -303,7 +305,7 @@ def visit_Lambda(self, node):
SPACE_PRECEDES_CLOSE_BRACKET = re.compile(r" \)")


def extract_lambda_source(f):
def _extract_lambda_source(f):
"""Extracts a single lambda expression from the string source. Returns a
string indicating an unknown body if it gets confused in any way.
Expand Down Expand Up @@ -439,6 +441,17 @@ def extract_lambda_source(f):
return source.strip()


def extract_lambda_source(f):
try:
return LAMBDA_SOURCE_CACHE[f]
except KeyError:
pass

source = _extract_lambda_source(f)
LAMBDA_SOURCE_CACHE[f] = source
return source


def get_pretty_function_description(f):
if isinstance(f, partial):
return pretty(f)
Expand Down Expand Up @@ -492,7 +505,7 @@ def repr_call(f, args, kwargs, *, reorder=True):
if repr_len > 30000:
warnings.warn(
"Generating overly large repr. This is an expensive operation, and with "
f"a length of {repr_len//1000} kB is is unlikely to be useful. Use -Wignore "
f"a length of {repr_len//1000} kB is unlikely to be useful. Use -Wignore "
"to ignore the warning, or -Werror to get a traceback.",
HypothesisWarning,
stacklevel=2,
Expand Down
11 changes: 6 additions & 5 deletions hypothesis-python/tests/cover/test_reflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,12 +541,10 @@ def test_required_args(target, args, kwargs, expected):
assert required_args(target, args, kwargs) == expected


# fmt: off
pi = "π"; is_str_pi = lambda x: x == pi # noqa: E702
# fmt: on


def test_can_handle_unicode_identifier_in_same_line_as_lambda_def():
# fmt: off
pi = "π"; is_str_pi = lambda x: x == pi # noqa: E702
# fmt: on
assert get_pretty_function_description(is_str_pi) == "lambda x: x == pi"


Expand All @@ -567,6 +565,9 @@ def test_does_not_crash_on_utf8_lambda_without_encoding(monkeypatch):
# has to fall back to assuming it's ASCII.

monkeypatch.setattr(reflection, "detect_encoding", None)
# fmt: off
pi = "π"; is_str_pi = lambda x: x == pi # noqa: E702
# fmt: on
assert get_pretty_function_description(is_str_pi) == "lambda x: <unknown>"


Expand Down

0 comments on commit 0a17774

Please sign in to comment.