Bug#1143382: requests-ratelimiter: FTBFS: E NameError: name 'RequestsCookieJar' is not defined
Santiago Vila <[email protected]> Sat, 01 Aug 2026 22:38:06 +0000
| Newsgroups | gmane.linux.debian.devel.bugs.rc |
|---|---|
| Message-ID | <E1wqILG-00DZP8-0N__45582.8337160469$1785624208$gmane$org@paradis.debian.org> |
Package: src:requests-ratelimiter
Version: 0.10.0-1
Severity: serious
Tags: ftbfs forky sid
Dear maintainer:
During a rebuild of all packages in unstable, this package failed to build.
Below you will find the last part of the build log (probably the most
relevant part, but not necessarily). If required, the full build log
is available here:
https://people.debian.org/~sanvila/build-logs/202608/
About the archive rebuild: The build was made on virtual machines from AWS,
using sbuild and a reduced chroot with only build-essential packages.
If you cannot reproduce the bug please contact me privately, as I
am willing to provide ssh access to a virtual machine where the bug is
fully reproducible.
If this is really a bug in one of the build-depends, please use
reassign and add an affects on src:requests-ratelimiter, so that this is still
visible in the BTS web page for this package.
Thanks.
--------------------------------------------------------------------------------
[...]
debian/rules clean
dh clean --buildsystem=pybuild
dh_auto_clean -O--buildsystem=pybuild
dh_autoreconf_clean -O--buildsystem=pybuild
dh_clean -O--buildsystem=pybuild
debian/rules binary
dh binary --buildsystem=pybuild
dh_update_autotools_config -O--buildsystem=pybuild
dh_autoreconf -O--buildsystem=pybuild
dh_auto_configure -O--buildsystem=pybuild
dh_auto_build -O--buildsystem=pybuild
I: pybuild plugin_pyproject:142: Building wheel for python3.13 with "build" module
I: pybuild base:385: python3.13 -m build --skip-dependency-check --no-isolation --wheel --outdir /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13_requests-ratelimiter
* Building wheel...
Successfully built requests_ratelimiter-0.10.0-py3-none-any.whl
I: pybuild plugin_pyproject:168: Unpacking wheel built for python3.13 with "installer" module
I: pybuild plugin_pyproject:142: Building wheel for python3.14 with "build" module
I: pybuild base:385: python3.14 -m build --skip-dependency-check --no-isolation --wheel --outdir /<<PKGBUILDDIR>>/.pybuild/cpython3_3.14_requests-ratelimiter
* Building wheel...
Successfully built requests_ratelimiter-0.10.0-py3-none-any.whl
I: pybuild plugin_pyproject:168: Unpacking wheel built for python3.14 with "installer" module
dh_auto_test -O--buildsystem=pybuild
I: pybuild base:385: cd /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13_requests-ratelimiter/build; python3.13 -m pytest test
============================= test session starts ==============================
platform linux -- Python 3.13.14, pytest-9.1.1, pluggy-1.6.0
rootdir: /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13_requests-ratelimiter/build
configfile: pyproject.toml
plugins: requests_mock-1.12.1, typeguard-4.4.4
collected 86 items
test/test_buckets.py ................. [ 19%]
test/test_exports.py . [ 20%]
test/test_integration.py ..... [ 26%]
test/test_requests_ratelimiter.py .....................F................ [ 70%]
......................... [100%]
=================================== FAILURES ===================================
___________________________ test_cache_with_limiter ____________________________
mock_sleep = <MagicMock name='sleep' id='140513336644272'>
tmp_path_factory = TempPathFactory(_given_basetemp=None, _trace=<pluggy._tracing.TagTracerSub object at 0x7fcbcf96c8a0>, _basetemp=PosixPath('/tmp/pytest-of-sbuild/pytest-0'), _retention_count=3, _retention_policy='all')
@patch_sleep
def test_cache_with_limiter(mock_sleep, tmp_path_factory):
"""Check that caching integration works as expected"""
class CachedLimiterSession(CacheMixin, LimiterMixin, Session):
pass
cache_path = tmp_path_factory.mktemp('pytest') / 'cache.db'
ratelimit_path = tmp_path_factory.mktemp('pytest') / 'rate_limit.db'
session = CachedLimiterSession(
per_second=5,
cache_name=str(cache_path),
bucket_class=SQLiteBucket,
bucket_kwargs={'path': ratelimit_path, **SQLITE_BUCKET_KWARGS},
)
session = mount_mock_adapter(session)
for _ in range(10):
> session.get(MOCKED_URL)
test/test_requests_ratelimiter.py:246:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3/dist-packages/requests_cache/session.py:133: in get
return self.request('GET', url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/session.py:189: in request
return super().request(method, url, *args, headers=headers, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests/sessions.py:651: in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/session.py:255: in send
response = self._send_and_cache(request, actions, cached_response, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/session.py:283: in _send_and_cache
self.cache.save_response(response, actions.cache_key, actions.expires)
/usr/lib/python3/dist-packages/requests_cache/backends/base.py:92: in save_response
self.responses[cache_key] = cached_response
^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/backends/sqlite.py:341: in __setitem__
self._write(key, value)
/usr/lib/python3/dist-packages/requests_cache/backends/sqlite.py:346: in _write
value = self.serialize(value)
^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/backends/sqlite.py:396: in serialize
value = super().serialize(value)
^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/backends/base.py:340: in serialize
return self.serializer.dumps(value) if self.serializer else value
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/serializers/pipeline.py:67: in dumps
value = step(value)
^^^^^^^^^^^
/usr/lib/python3.13/functools.py:974: in _method
return dispatch(args[0].__class__).__get__(obj, cls)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/serializers/cattrs.py:79: in _
response_dict = self.converter.unstructure(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/cattrs/converters.py:324: in unstructure
return self._unstructure_func.dispatch(
/usr/lib/python3/dist-packages/cattrs/dispatch.py:133: in dispatch_without_caching
res = self._function_dispatch.dispatch(typ)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/cattrs/dispatch.py:76: in dispatch
return handler(typ)
^^^^^^^^^^^^
/usr/lib/python3/dist-packages/cattrs/converters.py:1266: in gen_unstructure_attrs_fromdict
resolve_types(origin or cl)
/usr/lib/python3/dist-packages/attr/_funcs.py:487: in resolve_types
hints = typing.get_type_hints(cls, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3.13/typing.py:2481: in get_type_hints
value = _eval_type(value, base_globals, base_locals, base.__type_params__)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3.13/typing.py:474: in _eval_type
return t._evaluate(globalns, localns, type_params, recursive_guard=recursive_guard)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3.13/typing.py:1074: in _evaluate
eval(self.__forward_code__, globalns, localns),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E NameError: name 'RequestsCookieJar' is not defined
<string>:1: NameError
----------------------------- Captured stderr call -----------------------------
DEBUG:requests_ratelimiter.requests_ratelimiter:Creating Limiter with rates:
5/1000ms
------------------------------ Captured log call -------------------------------
DEBUG requests_ratelimiter.requests_ratelimiter:requests_ratelimiter.py:60 Creating Limiter with rates:
5/1000ms
=============================== warnings summary ===============================
test/test_requests_ratelimiter.py::test_cache_with_limiter
/usr/lib/python3/dist-packages/url_normalize/normalize_host.py:35: DeprecationWarning: Transitional processing has been removed from UTS #46. The transitional argument will be removed in a future version.
idna.encode(p, uts46=True, transitional=True).decode(charset)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED test/test_requests_ratelimiter.py::test_cache_with_limiter - NameError...
=================== 1 failed, 85 passed, 1 warning in 43.04s ===================
E: pybuild pybuild:485: test: plugin pyproject failed with: exit code=1: cd /<<PKGBUILDDIR>>/.pybuild/cpython3_3.13_requests-ratelimiter/build; python3.13 -m pytest test
I: pybuild base:385: cd /<<PKGBUILDDIR>>/.pybuild/cpython3_3.14_requests-ratelimiter/build; python3.14 -m pytest test
============================= test session starts ==============================
platform linux -- Python 3.14.6, pytest-9.1.1, pluggy-1.6.0
rootdir: /<<PKGBUILDDIR>>/.pybuild/cpython3_3.14_requests-ratelimiter/build
configfile: pyproject.toml
plugins: requests_mock-1.12.1, typeguard-4.4.4
collected 86 items
test/test_buckets.py ................. [ 19%]
test/test_exports.py . [ 20%]
test/test_integration.py ..... [ 26%]
test/test_requests_ratelimiter.py .....................F................ [ 70%]
......................... [100%]
=================================== FAILURES ===================================
___________________________ test_cache_with_limiter ____________________________
mock_sleep = <MagicMock name='sleep' id='140280038931296'>
tmp_path_factory = TempPathFactory(_given_basetemp=None, _trace=<pluggy._tracing.TagTracerSub object at 0x7f957e554510>, _basetemp=PosixPath('/tmp/pytest-of-sbuild/pytest-1'), _retention_count=3, _retention_policy='all')
@patch_sleep
def test_cache_with_limiter(mock_sleep, tmp_path_factory):
"""Check that caching integration works as expected"""
class CachedLimiterSession(CacheMixin, LimiterMixin, Session):
pass
cache_path = tmp_path_factory.mktemp('pytest') / 'cache.db'
ratelimit_path = tmp_path_factory.mktemp('pytest') / 'rate_limit.db'
session = CachedLimiterSession(
per_second=5,
cache_name=str(cache_path),
bucket_class=SQLiteBucket,
bucket_kwargs={'path': ratelimit_path, **SQLITE_BUCKET_KWARGS},
)
session = mount_mock_adapter(session)
for _ in range(10):
> session.get(MOCKED_URL)
test/test_requests_ratelimiter.py:246:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3/dist-packages/requests_cache/session.py:133: in get
return self.request('GET', url, params=params, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/session.py:189: in request
return super().request(method, url, *args, headers=headers, **kwargs) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests/sessions.py:651: in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/session.py:255: in send
response = self._send_and_cache(request, actions, cached_response, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/session.py:283: in _send_and_cache
self.cache.save_response(response, actions.cache_key, actions.expires)
/usr/lib/python3/dist-packages/requests_cache/backends/base.py:92: in save_response
self.responses[cache_key] = cached_response
^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/backends/sqlite.py:341: in __setitem__
self._write(key, value)
/usr/lib/python3/dist-packages/requests_cache/backends/sqlite.py:346: in _write
value = self.serialize(value)
^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/backends/sqlite.py:396: in serialize
value = super().serialize(value)
^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/backends/base.py:340: in serialize
return self.serializer.dumps(value) if self.serializer else value
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/serializers/pipeline.py:67: in dumps
value = step(value)
^^^^^^^^^^^
/usr/lib/python3.14/functools.py:1069: in __call__
return self._dispatch(args[0].__class__).__get__(self._obj, self._cls)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/requests_cache/serializers/cattrs.py:79: in _
response_dict = self.converter.unstructure(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/cattrs/converters.py:324: in unstructure
return self._unstructure_func.dispatch(
/usr/lib/python3/dist-packages/cattrs/dispatch.py:133: in dispatch_without_caching
res = self._function_dispatch.dispatch(typ)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3/dist-packages/cattrs/dispatch.py:76: in dispatch
return handler(typ)
^^^^^^^^^^^^
/usr/lib/python3/dist-packages/cattrs/converters.py:1266: in gen_unstructure_attrs_fromdict
resolve_types(origin or cl)
/usr/lib/python3/dist-packages/attr/_funcs.py:487: in resolve_types
hints = typing.get_type_hints(cls, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3.14/typing.py:2391: in get_type_hints
value = _eval_type(value, base_globals, base_locals, (),
/usr/lib/python3.14/typing.py:461: in _eval_type
return evaluate_forward_ref(t, globals=globalns, locals=localns,
/usr/lib/python3.14/typing.py:1000: in evaluate_forward_ref
value = forward_ref.evaluate(globals=globals, locals=locals,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ForwardRef('RequestsCookieJar', is_class=True)
globals = {'__module__': 'requests.models', '__firstlineno__': 730, '__annotations__': {'_content': 'bytes | Literal[False] | No..., '__doc__': "The :class:`Response <Response>` object, which contains a\nserver's response to an HTTP request.\n", ...}
locals = {'__name__': 'requests.models', '__doc__': '\nrequests.models\n~~~~~~~~~~~~~~~\n\nThis module contains the primary obj..., '__package__': 'requests', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f957e7b0c50>, ...}
type_params = ()
owner = <class 'requests_cache.models.response.CachedResponse'>
format = <Format.VALUE: 1>
def evaluate(
self,
*,
globals=None,
locals=None,
type_params=None,
owner=None,
format=Format.VALUE,
):
"""Evaluate the forward reference and return the value.
If the forward reference cannot be evaluated, raise an exception.
"""
match format:
case Format.STRING:
return self.__resolved_str__
case Format.VALUE:
is_forwardref_format = False
case Format.FORWARDREF:
is_forwardref_format = True
case _:
raise NotImplementedError(format)
if isinstance(self.__cell__, types.CellType):
try:
return self.__cell__.cell_contents
except ValueError:
pass
if owner is None:
owner = self.__owner__
if globals is None and self.__forward_module__ is not None:
globals = getattr(
sys.modules.get(self.__forward_module__, None), "__dict__", None
)
if globals is None:
globals = self.__globals__
if globals is None:
if isinstance(owner, type):
module_name = getattr(owner, "__module__", None)
if module_name:
module = sys.modules.get(module_name, None)
if module:
globals = getattr(module, "__dict__", None)
elif isinstance(owner, types.ModuleType):
globals = getattr(owner, "__dict__", None)
elif callable(owner):
globals = getattr(owner, "__globals__", None)
# If we pass None to eval() below, the globals of this module are used.
if globals is None:
globals = {}
if type_params is None and owner is not None:
type_params = getattr(owner, "__type_params__", None)
if locals is None:
locals = {}
if isinstance(owner, type):
locals.update(vars(owner))
elif (
type_params is not None
or isinstance(self.__cell__, dict)
or self.__extra_names__
):
# Create a new locals dict if necessary,
# to avoid mutating the argument.
locals = dict(locals)
# "Inject" type parameters into the local namespace
# (unless they are shadowed by assignments *in* the local namespace),
# as a way of emulating annotation scopes when calling `eval()`
if type_params is not None:
for param in type_params:
locals.setdefault(param.__name__, param)
# Similar logic can be used for nonlocals, which should not
# override locals.
if isinstance(self.__cell__, dict):
for cell_name, cell in self.__cell__.items():
try:
cell_value = cell.cell_contents
except ValueError:
pass
else:
locals.setdefault(cell_name, cell_value)
if self.__extra_names__:
locals.update(self.__extra_names__)
arg = self.__forward_arg__
if arg.isidentifier() and not keyword.iskeyword(arg):
if arg in locals:
return locals[arg]
elif arg in globals:
return globals[arg]
elif hasattr(builtins, arg):
return getattr(builtins, arg)
elif is_forwardref_format:
return self
else:
> raise NameError(_NAME_ERROR_MSG.format(name=arg), name=arg)
E NameError: name 'RequestsCookieJar' is not defined
/usr/lib/python3.14/annotationlib.py:203: NameError
----------------------------- Captured stderr call -----------------------------
DEBUG:requests_ratelimiter.requests_ratelimiter:Creating Limiter with rates:
5/1000ms
------------------------------ Captured log call -------------------------------
DEBUG requests_ratelimiter.requests_ratelimiter:requests_ratelimiter.py:60 Creating Limiter with rates:
5/1000ms
=============================== warnings summary ===============================
test/test_requests_ratelimiter.py::test_cache_with_limiter
/usr/lib/python3/dist-packages/url_normalize/normalize_host.py:35: DeprecationWarning: Transitional processing has been removed from UTS #46. The transitional argument will be removed in a future version.
idna.encode(p, uts46=True, transitional=True).decode(charset)
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED test/test_requests_ratelimiter.py::test_cache_with_limiter - NameError...
=================== 1 failed, 85 passed, 1 warning in 43.05s ===================
E: pybuild pybuild:485: test: plugin pyproject failed with: exit code=1: cd /<<PKGBUILDDIR>>/.pybuild/cpython3_3.14_requests-ratelimiter/build; python3.14 -m pytest test
dh_auto_test: error: pybuild --test --test-pytest -i python{version} -p "3.13 3.14" --parallel=2 returned exit code 13
make: *** [debian/rules:6: binary] Error 25
dpkg-buildpackage: error: debian/rules binary subprocess failed with exit status 2
--------------------------------------------------------------------------------