Skip to content

Commit 7858ab4

Browse files
authored
chore: Revert "feat: add caching to GapicCallable (#666)" (#744)
This reverts commit 1695119.
1 parent a26313e commit 7858ab4

File tree

2 files changed

+44
-57
lines changed

2 files changed

+44
-57
lines changed

google/api_core/gapic_v1/method.py

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,24 @@ class _MethodDefault(enum.Enum):
4242
so the default should be used."""
4343

4444

45+
def _is_not_none_or_false(value):
46+
return value is not None and value is not False
47+
48+
49+
def _apply_decorators(func, decorators):
50+
"""Apply a list of decorators to a given function.
51+
52+
``decorators`` may contain items that are ``None`` or ``False`` which will
53+
be ignored.
54+
"""
55+
filtered_decorators = filter(_is_not_none_or_false, reversed(decorators))
56+
57+
for decorator in filtered_decorators:
58+
func = decorator(func)
59+
60+
return func
61+
62+
4563
class _GapicCallable(object):
4664
"""Callable that applies retry, timeout, and metadata logic.
4765
@@ -73,53 +91,44 @@ def __init__(
7391
):
7492
self._target = target
7593
self._retry = retry
76-
if isinstance(timeout, (int, float)):
77-
timeout = TimeToDeadlineTimeout(timeout=timeout)
7894
self._timeout = timeout
7995
self._compression = compression
80-
self._metadata = list(metadata) if metadata is not None else None
96+
self._metadata = metadata
8197

8298
def __call__(
8399
self, *args, timeout=DEFAULT, retry=DEFAULT, compression=DEFAULT, **kwargs
84100
):
85101
"""Invoke the low-level RPC with retry, timeout, compression, and metadata."""
86102

87-
if compression is DEFAULT:
88-
compression = self._compression
89-
if compression is not None:
90-
kwargs["compression"] = compression
103+
if retry is DEFAULT:
104+
retry = self._retry
91105

92-
# Add the user agent metadata to the call.
93-
if self._metadata is not None:
94-
try:
95-
# attempt to concatenate default metadata with user-provided metadata
96-
kwargs["metadata"] = [*kwargs["metadata"], *self._metadata]
97-
except (KeyError, TypeError):
98-
# if metadata is not provided, use just the default metadata
99-
kwargs["metadata"] = self._metadata
100-
101-
call = self._build_wrapped_call(timeout, retry)
102-
return call(*args, **kwargs)
103-
104-
@functools.lru_cache(maxsize=4)
105-
def _build_wrapped_call(self, timeout, retry):
106-
"""
107-
Build a wrapped callable that applies retry, timeout, and metadata logic.
108-
"""
109-
wrapped_func = self._target
110106
if timeout is DEFAULT:
111107
timeout = self._timeout
112-
elif isinstance(timeout, (int, float)):
108+
109+
if compression is DEFAULT:
110+
compression = self._compression
111+
112+
if isinstance(timeout, (int, float)):
113113
timeout = TimeToDeadlineTimeout(timeout=timeout)
114-
if timeout is not None:
115-
wrapped_func = timeout(wrapped_func)
116114

117-
if retry is DEFAULT:
118-
retry = self._retry
119-
if retry is not None:
120-
wrapped_func = retry(wrapped_func)
115+
# Apply all applicable decorators.
116+
wrapped_func = _apply_decorators(self._target, [retry, timeout])
117+
118+
# Add the user agent metadata to the call.
119+
if self._metadata is not None:
120+
metadata = kwargs.get("metadata", [])
121+
# Due to the nature of invocation, None should be treated the same
122+
# as not specified.
123+
if metadata is None:
124+
metadata = []
125+
metadata = list(metadata)
126+
metadata.extend(self._metadata)
127+
kwargs["metadata"] = metadata
128+
if self._compression is not None:
129+
kwargs["compression"] = compression
121130

122-
return wrapped_func
131+
return wrapped_func(*args, **kwargs)
123132

124133

125134
def wrap_method(
@@ -193,9 +202,8 @@ def get_topic(name, timeout=None):
193202
194203
Args:
195204
func (Callable[Any]): The function to wrap. It should accept an
196-
optional ``timeout`` (google.api_core.timeout.Timeout) argument.
197-
If ``metadata`` is not ``None``, it should accept a ``metadata``
198-
(Sequence[Tuple[str, str]]) argument.
205+
optional ``timeout`` argument. If ``metadata`` is not ``None``, it
206+
should accept a ``metadata`` argument.
199207
default_retry (Optional[google.api_core.Retry]): The default retry
200208
strategy. If ``None``, the method will not retry by default.
201209
default_timeout (Optional[google.api_core.Timeout]): The default

tests/unit/gapic/test_method.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -222,24 +222,3 @@ def test_wrap_method_with_call_not_supported():
222222
with pytest.raises(ValueError) as exc_info:
223223
google.api_core.gapic_v1.method.wrap_method(method, with_call=True)
224224
assert "with_call=True is only supported for unary calls" in str(exc_info.value)
225-
226-
227-
def test_benchmark_gapic_call():
228-
"""
229-
Ensure the __call__ method performance does not regress from expectations
230-
231-
__call__ builds a new wrapped function using passed-in timeout and retry, but
232-
subsequent calls are cached
233-
234-
Note: The threshold has been tuned for the CI workers. Test may flake on
235-
slower hardware
236-
"""
237-
from google.api_core.gapic_v1.method import _GapicCallable
238-
from google.api_core.retry import Retry
239-
from timeit import timeit
240-
241-
gapic_callable = _GapicCallable(
242-
lambda *a, **k: 1, retry=Retry(), timeout=1010, compression=False
243-
)
244-
avg_time = timeit(lambda: gapic_callable(), number=10_000)
245-
assert avg_time < 0.4

0 commit comments

Comments
 (0)