jenkins-bot has submitted this change. (
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1353297?usp=email )
Change subject: api: Cache constructor argument introspection per request class
......................................................................
api: Cache constructor argument introspection per request class
Request.clean_kwargs inspects constructor signatures on every call to
separate request options from MediaWiki API parameters. Cache the
argument names per class as a frozenset so repeated generator setup
reuses the result without sharing mutable state.
Keep the existing MRO traversal and argument classification.
Change-Id: Ia5a5177b83edae6aa548cd7d16a4c8682f1a325a
---
M pywikibot/data/api/_requests.py
M tests/dry_api_tests.py
2 files changed, 32 insertions(+), 9 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/data/api/_requests.py b/pywikibot/data/api/_requests.py
index 2c13277..c800e32 100644
--- a/pywikibot/data/api/_requests.py
+++ b/pywikibot/data/api/_requests.py
@@ -20,6 +20,7 @@
from collections.abc import Callable, MutableMapping
from contextlib import suppress
from email.mime.nonmultipart import MIMENonMultipart
+from functools import cache
from pathlib import Path
from typing import Any, NoReturn
from urllib.parse import unquote, urlencode
@@ -297,6 +298,20 @@
'"parameters" parameter.', DeprecationWarning, 3)
@classmethod
+ @cache
+ def _get_constructor_args(cls) -> frozenset[str]:
+ """Return cached constructor argument names for this request class."""
+ args = set()
+ for super_cls in inspect.getmro(cls):
+ if not super_cls.__name__.endswith('Request'):
+ break
+ args |= set(inspect.getfullargspec(super_cls.__init__).args)
+ else:
+ raise ValueError(f'Request was not a super class of {cls!r}')
+
+ return frozenset(args - {'self'})
+
+ @classmethod
def clean_kwargs(cls, kwargs: dict) -> dict:
"""Convert keyword arguments into new parameters mode.
@@ -313,15 +328,7 @@
if 'expiry' in kwargs and kwargs['expiry'] is None:
del kwargs['expiry']
- args = set()
- for super_cls in inspect.getmro(cls):
- if not super_cls.__name__.endswith('Request'):
- break
- args |= set(inspect.getfullargspec(super_cls.__init__).args)
- else:
- raise ValueError(f'Request was not a super class of {cls!r}')
-
- args -= {'self'}
+ args = cls._get_constructor_args()
old_kwargs = set(kwargs)
# all kwargs defined above but not in args indicate 'kwargs' mode
if old_kwargs - args:
diff --git a/tests/dry_api_tests.py b/tests/dry_api_tests.py
index 21eb37e..9e6b6a8 100755
--- a/tests/dry_api_tests.py
+++ b/tests/dry_api_tests.py
@@ -423,6 +423,22 @@
dry = True
+ def test_cached_constructor_args(self) -> None:
+ """Reuse constructor arguments without sharing subclass results."""
+ kwargs = {'site': self.site, 'parameters': {'action': 'query'}}
+ cached_kwargs = dict(kwargs, expiry=1)
+ Request._get_constructor_args.cache_clear()
+ self.addCleanup(Request._get_constructor_args.cache_clear)
+ self.assertEqual(Request.clean_kwargs(kwargs), kwargs)
+ self.assertEqual(CachedRequest.clean_kwargs(cached_kwargs),
+ cached_kwargs)
+
+ with patch('pywikibot.data.api._requests.inspect.getfullargspec',
+ side_effect=AssertionError('Repeated introspection')):
+ self.assertEqual(Request.clean_kwargs(kwargs), kwargs)
+ self.assertEqual(CachedRequest.clean_kwargs(cached_kwargs),
+ cached_kwargs)
+
def test_query_constructor(self) -> None:
"""Test QueryGenerator constructor."""
q_gen1 = QueryGenerator(
--
To view, visit
https://gerrit.wikimedia.org/r/c/pywikibot/core/+/1353297?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.wikimedia.org/r/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ia5a5177b83edae6aa548cd7d16a4c8682f1a325a
Gerrit-Change-Number: 1353297
Gerrit-PatchSet: 3
Gerrit-Owner: Mahveotm <[email protected]>
Gerrit-Reviewer: Xqt <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
Pywikibot-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]