Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-CacheControl for openSUSE:Factory checked in at 2021-12-09 19:45:09 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-CacheControl (Old) and /work/SRC/openSUSE:Factory/.python-CacheControl.new.2520 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-CacheControl" Thu Dec 9 19:45:09 2021 rev:9 rq:935720 version:0.12.10 Changes: -------- --- /work/SRC/openSUSE:Factory/python-CacheControl/python-CacheControl.changes 2020-06-10 00:44:49.218395200 +0200 +++ /work/SRC/openSUSE:Factory/.python-CacheControl.new.2520/python-CacheControl.changes 2021-12-09 19:45:19.281124939 +0100 @@ -1,0 +2,7 @@ +Sat Dec 4 21:10:51 UTC 2021 - Ben Greiner <c...@bnavigator.de> + +- Update to v0.12.10 + * Dropped support for Python 2.7, 3.4, 3.5. + * Reduced memory usage when caching large files. + +------------------------------------------------------------------- Old: ---- CacheControl-0.12.6.tar.gz New: ---- CacheControl-0.12.10.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-CacheControl.spec ++++++ --- /var/tmp/diff_new_pack.9ysOS8/_old 2021-12-09 19:45:19.949125260 +0100 +++ /var/tmp/diff_new_pack.9ysOS8/_new 2021-12-09 19:45:19.949125260 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-CacheControl # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,9 +16,10 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} +%{?!python_module:%define python_module() python3-%{**}} +%define skip_python2 1 Name: python-CacheControl -Version: 0.12.6 +Version: 0.12.10 Release: 0 Summary: Caching library for Python requests License: Apache-2.0 @@ -28,22 +29,21 @@ BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros -Requires: python-msgpack +Requires: python-msgpack >= 0.5.2 Requires: python-requests +Provides: python-cachecontrol = %{version}-%{release} Requires(post): update-alternatives -Requires(postun): update-alternatives +Requires(postun):update-alternatives Recommends: python-lockfile >= 0.9 Suggests: python-redis >= 2.10.5 BuildArch: noarch # SECTION test requirements -## cherrypy is python3 only from 18.x series -BuildRequires: python3-CherryPy -BuildRequires: python3-lockfile >= 0.9 -BuildRequires: python3-mock -BuildRequires: python3-msgpack -BuildRequires: python3-pytest -BuildRequires: python3-redis >= 2.10.5 -BuildRequires: python3-requests +BuildRequires: %{python_module CherryPy} +BuildRequires: %{python_module lockfile >= 0.9} +BuildRequires: %{python_module msgpack >= 0.5.2} +BuildRequires: %{python_module pytest} +BuildRequires: %{python_module redis >= 2.10.5} +BuildRequires: %{python_module requests} # /SECTION %python_subpackages @@ -53,6 +53,7 @@ %prep %setup -q -n cachecontrol-%{version} +sed -i -e 's/^from mock/from unittest.mock/' -e 's/^import mock/from unittest import mock/' tests/*.py %build %python_build @@ -64,7 +65,7 @@ %check # test_file_cache_recognizes_consumed_file_handle uses httpbin.org directly -PYTHONPATH=%{buildroot}%{python3_sitelib} py.test-%{python3_bin_suffix} -v -k 'not test_file_cache_recognizes_consumed_file_handle' +%pytest -v -k 'not test_file_cache_recognizes_consumed_file_handle' %post %python_install_alternative doesitcache @@ -76,6 +77,7 @@ %license LICENSE.txt %doc README.rst %python_alternative %{_bindir}/doesitcache -%{python_sitelib}/* +%{python_sitelib}/cachecontrol +%{python_sitelib}/CacheControl-%{version}*-info %changelog ++++++ CacheControl-0.12.6.tar.gz -> CacheControl-0.12.10.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/.bumpversion.cfg new/cachecontrol-0.12.10/.bumpversion.cfg --- old/cachecontrol-0.12.6/.bumpversion.cfg 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/.bumpversion.cfg 2021-11-05 18:07:09.000000000 +0100 @@ -1,6 +1,5 @@ [bumpversion] -current_version = 0.12.6 +current_version = 0.12.10 files = setup.py cachecontrol/__init__.py docs/conf.py commit = True tag = True - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/.github/workflows/tests.yml new/cachecontrol-0.12.10/.github/workflows/tests.yml --- old/cachecontrol-0.12.6/.github/workflows/tests.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/cachecontrol-0.12.10/.github/workflows/tests.yml 2021-11-05 18:07:09.000000000 +0100 @@ -0,0 +1,34 @@ +--- +name: CI + +on: + push: + branches: ["master"] + pull_request: + branches: ["master"] + workflow_dispatch: + +jobs: + tests: + name: "Python ${{ matrix.python-version }} ${{ matrix.os }}" + runs-on: "${{ matrix.os }}" + + strategy: + matrix: + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + os: ["macos-10.15", "windows-latest", "ubuntu-latest"] + + steps: + - uses: "actions/checkout@v2" + - uses: "actions/setup-python@v2" + with: + python-version: "${{ matrix.python-version }}" + - name: "Install dependencies" + run: | + python -VV + python -m site + python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade virtualenv tox tox-gh-actions + + - name: "Run tox targets for ${{ matrix.python-version }}" + run: "python -m tox" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/.gitignore new/cachecontrol-0.12.10/.gitignore --- old/cachecontrol-0.12.6/.gitignore 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/.gitignore 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + .DS_Store *.pyc *.pyo diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/.travis.yml new/cachecontrol-0.12.10/.travis.yml --- old/cachecontrol-0.12.6/.travis.yml 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/.travis.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,13 +0,0 @@ -language: python -sudo: false - -python: - - 2.7 - - 3.4 - - 3.5 - - 3.6 - # - 3.7 - -install: pip install tox-travis - -script: tox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/CONTRIBUTORS.rst new/cachecontrol-0.12.10/CONTRIBUTORS.rst --- old/cachecontrol-0.12.6/CONTRIBUTORS.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/CONTRIBUTORS.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + ============== Contributors ============== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/LICENSE.txt new/cachecontrol-0.12.10/LICENSE.txt --- old/cachecontrol-0.12.6/LICENSE.txt 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/LICENSE.txt 2021-11-05 18:07:09.000000000 +0100 @@ -1,4 +1,4 @@ -Copyright 2015 Eric Larson +Copyright 2012-2021 Eric Larson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -8,8 +8,6 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -implied. - +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/MANIFEST.in new/cachecontrol-0.12.10/MANIFEST.in --- old/cachecontrol-0.12.6/MANIFEST.in 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 @@ -1 +0,0 @@ -include LICENSE.txt \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/Makefile new/cachecontrol-0.12.10/Makefile --- old/cachecontrol-0.12.6/Makefile 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/Makefile 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + VENV=.venv VENV_CMD=python3 -m venv ACTIVATE = $(VENV)/bin/activate @@ -5,11 +9,11 @@ BUMPTYPE=patch -$(VENV)/bin/pip: +$(VENV)/bin/pip3: $(VENV_CMD) $(VENV) -bootstrap: $(VENV)/bin/pip - $(VENV)/bin/pip install -r dev_requirements.txt +bootstrap: $(VENV)/bin/pip3 + $(VENV)/bin/pip3 install -r dev_requirements.txt format: $(VENV)/bin/black . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/README.rst new/cachecontrol-0.12.10/README.rst --- old/cachecontrol-0.12.6/README.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/README.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + ============== CacheControl ============== @@ -38,5 +43,5 @@ For more info, check out the docs_ .. _docs: http://cachecontrol.readthedocs.org/en/latest/ -.. _httplib2: https://github.com/jcgregorio/httplib2 +.. _httplib2: https://github.com/httplib2/httplib2 .. _requests: http://docs.python-requests.org/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/__init__.py new/cachecontrol-0.12.10/cachecontrol/__init__.py --- old/cachecontrol-0.12.6/cachecontrol/__init__.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/__init__.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,11 +1,18 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + """CacheControl import Interface. Make it easy to import from cachecontrol without long namespaces. """ __author__ = "Eric Larson" __email__ = "e...@ionrock.org" -__version__ = "0.12.6" +__version__ = "0.12.10" from .wrapper import CacheControl from .adapter import CacheControlAdapter from .controller import CacheController + +import logging +logging.getLogger(__name__).addHandler(logging.NullHandler()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/_cmd.py new/cachecontrol-0.12.10/cachecontrol/_cmd.py --- old/cachecontrol-0.12.6/cachecontrol/_cmd.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/_cmd.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import logging import requests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/adapter.py new/cachecontrol-0.12.10/cachecontrol/adapter.py --- old/cachecontrol-0.12.6/cachecontrol/adapter.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/adapter.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,16 +1,20 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import types import functools import zlib from requests.adapters import HTTPAdapter -from .controller import CacheController +from .controller import CacheController, PERMANENT_REDIRECT_STATUSES from .cache import DictCache from .filewrapper import CallbackFileWrapper class CacheControlAdapter(HTTPAdapter): - invalidating_methods = {"PUT", "DELETE"} + invalidating_methods = {"PUT", "PATCH", "DELETE"} def __init__( self, @@ -93,7 +97,7 @@ response = cached_response # We always cache the 301 responses - elif response.status == 301: + elif int(response.status) in PERMANENT_REDIRECT_STATUSES: self.controller.cache_response(request, response) else: # Wrap the response file with a wrapper that will cache the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/cache.py new/cachecontrol-0.12.10/cachecontrol/cache.py --- old/cachecontrol-0.12.6/cachecontrol/cache.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/cache.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + """ The cache object API for implementing caches. The default is a thread safe in-memory dictionary. @@ -10,7 +14,7 @@ def get(self, key): raise NotImplementedError() - def set(self, key, value): + def set(self, key, value, expires=None): raise NotImplementedError() def delete(self, key): @@ -29,7 +33,7 @@ def get(self, key): return self.data.get(key, None) - def set(self, key, value): + def set(self, key, value, expires=None): with self.lock: self.data.update({key: value}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/caches/__init__.py new/cachecontrol-0.12.10/cachecontrol/caches/__init__.py --- old/cachecontrol-0.12.6/cachecontrol/caches/__init__.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/caches/__init__.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,2 +1,6 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + from .file_cache import FileCache # noqa from .redis_cache import RedisCache # noqa diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/caches/file_cache.py new/cachecontrol-0.12.10/cachecontrol/caches/file_cache.py --- old/cachecontrol-0.12.6/cachecontrol/caches/file_cache.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/caches/file_cache.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import hashlib import os from textwrap import dedent @@ -114,7 +118,7 @@ except FileNotFoundError: return None - def set(self, key, value): + def set(self, key, value, expires=None): name = self._fn(key) # Make sure the directory exists diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/caches/redis_cache.py new/cachecontrol-0.12.10/cachecontrol/caches/redis_cache.py --- old/cachecontrol-0.12.6/cachecontrol/caches/redis_cache.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/caches/redis_cache.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + from __future__ import division from datetime import datetime diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/compat.py new/cachecontrol-0.12.10/cachecontrol/compat.py --- old/cachecontrol-0.12.6/cachecontrol/compat.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/compat.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + try: from urllib.parse import urljoin except ImportError: @@ -9,7 +13,6 @@ except ImportError: import pickle - # Handle the case where the requests module has been patched to not have # urllib3 bundled as part of its source. try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/controller.py new/cachecontrol-0.12.10/cachecontrol/controller.py --- old/cachecontrol-0.12.6/cachecontrol/controller.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/controller.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + """ The httplib2 algorithms ported for use with requests. """ @@ -17,6 +21,8 @@ URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?") +PERMANENT_REDIRECT_STATUSES = (301, 308) + def parse_uri(uri): """Parses a URI using the regex given in Appendix B of RFC 3986. @@ -37,7 +43,7 @@ self.cache = DictCache() if cache is None else cache self.cache_etags = cache_etags self.serializer = serializer or Serializer() - self.cacheable_status_codes = status_codes or (200, 203, 300, 301) + self.cacheable_status_codes = status_codes or (200, 203, 300, 301, 308) @classmethod def _urlnorm(cls, uri): @@ -147,17 +153,18 @@ logger.warning("Cache entry deserialization failed, entry ignored") return False - # If we have a cached 301, return it immediately. We don't - # need to test our response for other headers b/c it is + # If we have a cached permanent redirect, return it immediately. We + # don't need to test our response for other headers b/c it is # intrinsically "cacheable" as it is Permanent. + # # See: # https://tools.ietf.org/html/rfc7231#section-6.4.2 # # Client can try to refresh the value by repeating the request # with cache busting headers as usual (ie no-cache). - if resp.status == 301: + if int(resp.status) in PERMANENT_REDIRECT_STATUSES: msg = ( - 'Returning cached "301 Moved Permanently" response ' + "Returning cached permanent redirect response " "(ignoring date and etag information)" ) logger.debug(msg) @@ -261,6 +268,11 @@ response_headers = CaseInsensitiveDict(response.headers) + if "date" in response_headers: + date = calendar.timegm(parsedate_tz(response_headers["date"])) + else: + date = 0 + # If we've been given a body, our response has a Content-Length, that # Content-Length is valid then we can check to see if the body we've # been given matches the expected size, and if it doesn't we'll just @@ -304,35 +316,62 @@ # If we've been given an etag, then keep the response if self.cache_etags and "etag" in response_headers: + expires_time = 0 + if response_headers.get("expires"): + expires = parsedate_tz(response_headers["expires"]) + if expires is not None: + expires_time = calendar.timegm(expires) - date + + expires_time = max(expires_time, 14 * 86400) + + logger.debug("etag object cached for {0} seconds".format(expires_time)) logger.debug("Caching due to etag") self.cache.set( - cache_url, self.serializer.dumps(request, response, body=body) + cache_url, + self.serializer.dumps(request, response, body), + expires=expires_time, ) - # Add to the cache any 301s. We do this before looking that - # the Date headers. - elif response.status == 301: - logger.debug("Caching permanant redirect") - self.cache.set(cache_url, self.serializer.dumps(request, response)) + # Add to the cache any permanent redirects. We do this before looking + # that the Date headers. + elif int(response.status) in PERMANENT_REDIRECT_STATUSES: + logger.debug("Caching permanent redirect") + self.cache.set(cache_url, self.serializer.dumps(request, response, b"")) # Add to the cache if the response headers demand it. If there # is no date header then we can't do anything about expiring # the cache. elif "date" in response_headers: + date = calendar.timegm(parsedate_tz(response_headers["date"])) # cache when there is a max-age > 0 if "max-age" in cc and cc["max-age"] > 0: logger.debug("Caching b/c date exists and max-age > 0") + expires_time = cc["max-age"] self.cache.set( - cache_url, self.serializer.dumps(request, response, body=body) + cache_url, + self.serializer.dumps(request, response, body), + expires=expires_time, ) # If the request can expire, it means we should cache it # in the meantime. elif "expires" in response_headers: if response_headers["expires"]: - logger.debug("Caching b/c of expires header") + expires = parsedate_tz(response_headers["expires"]) + if expires is not None: + expires_time = calendar.timegm(expires) - date + else: + expires_time = None + + logger.debug( + "Caching b/c of expires header. expires in {0} seconds".format( + expires_time + ) + ) self.cache.set( - cache_url, self.serializer.dumps(request, response, body=body) + cache_url, + self.serializer.dumps(request, response, body=body), + expires=expires_time, ) def update_cached_response(self, request, response): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/filewrapper.py new/cachecontrol-0.12.10/cachecontrol/filewrapper.py --- old/cachecontrol-0.12.6/cachecontrol/filewrapper.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/filewrapper.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,4 +1,9 @@ -from io import BytesIO +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + +from tempfile import NamedTemporaryFile +import mmap class CallbackFileWrapper(object): @@ -11,10 +16,17 @@ This class uses members with a double underscore (__) leading prefix so as not to accidentally shadow an attribute. + + The data is stored in a temporary file until it is all available. As long + as the temporary files directory is disk-based (sometimes it's a + memory-backed-``tmpfs`` on Linux), data will be unloaded to disk if memory + pressure is high. For small files the disk usually won't be used at all, + it'll all be in the filesystem memory cache, so there should be no + performance impact. """ def __init__(self, fp, callback): - self.__buf = BytesIO() + self.__buf = NamedTemporaryFile("rb+", delete=True) self.__fp = fp self.__callback = callback @@ -49,7 +61,19 @@ def _close(self): if self.__callback: - self.__callback(self.__buf.getvalue()) + if self.__buf.tell() == 0: + # Empty file: + result = b"" + else: + # Return the data without actually loading it into memory, + # relying on Python's buffer API and mmap(). mmap() just gives + # a view directly into the filesystem's memory cache, so it + # doesn't result in duplicate memory use. + self.__buf.seek(0, 0) + result = memoryview( + mmap.mmap(self.__buf.fileno(), 0, access=mmap.ACCESS_READ) + ) + self.__callback(result) # We assign this to None here, because otherwise we can get into # really tricky problems where the CPython interpreter dead locks @@ -58,9 +82,16 @@ # and allows the garbage collector to do it's thing normally. self.__callback = None + # Closing the temporary file releases memory and frees disk space. + # Important when caching big files. + self.__buf.close() + def read(self, amt=None): data = self.__fp.read(amt) - self.__buf.write(data) + if data: + # We may be dealing with b'', a sign that things are over: + # it's passed e.g. after we've already closed self.__buf. + self.__buf.write(data) if self.__is_fp_closed(): self._close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/heuristics.py new/cachecontrol-0.12.10/cachecontrol/heuristics.py --- old/cachecontrol-0.12.6/cachecontrol/heuristics.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/heuristics.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import calendar import time diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/serialize.py new/cachecontrol-0.12.10/cachecontrol/serialize.py --- old/cachecontrol-0.12.6/cachecontrol/serialize.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/serialize.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import base64 import io import json @@ -17,24 +21,18 @@ return _b64_decode_bytes(s).decode("utf8") -class Serializer(object): +_default_body_read = object() + +class Serializer(object): def dumps(self, request, response, body=None): response_headers = CaseInsensitiveDict(response.headers) if body is None: + # When a body isn't passed in, we'll read the response. We + # also update the response with a new file handler to be + # sure it acts as though it was never read. body = response.read(decode_content=False) - - # NOTE: 99% sure this is dead code. I'm only leaving it - # here b/c I don't have a test yet to prove - # it. Basically, before using - # `cachecontrol.filewrapper.CallbackFileWrapper`, - # this made an effort to reset the file handle. The - # `CallbackFileWrapper` short circuits this code by - # setting the body as the content is consumed, the - # result being a `body` argument is *always* passed - # into cache_response, and in turn, - # `Serializer.dump`. response._fp = io.BytesIO(body) # NOTE: This is all a bit weird, but it's really important that on diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/cachecontrol/wrapper.py new/cachecontrol-0.12.10/cachecontrol/wrapper.py --- old/cachecontrol-0.12.6/cachecontrol/wrapper.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/cachecontrol/wrapper.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + from .adapter import CacheControlAdapter from .cache import DictCache diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/dev_requirements.txt new/cachecontrol-0.12.10/dev_requirements.txt --- old/cachecontrol-0.12.6/dev_requirements.txt 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/dev_requirements.txt 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + -e . tox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/Makefile new/cachecontrol-0.12.10/docs/Makefile --- old/cachecontrol-0.12.6/docs/Makefile 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/Makefile 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + # Makefile for Sphinx documentation # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/conf.py new/cachecontrol-0.12.10/docs/conf.py --- old/cachecontrol-0.12.6/docs/conf.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/conf.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,5 +1,9 @@ # -*- coding: utf-8 -*- + +# SPDX-FileCopyrightText: 2015 Eric Larson # +# SPDX-License-Identifier: Apache-2.0 + # CacheControl documentation build configuration file, created by # sphinx-quickstart on Mon Nov 4 15:01:23 2013. # @@ -48,9 +52,9 @@ # built documents. # # The short X.Y version. -version = "0.12.6" +version = "0.12.10" # The full version, including alpha/beta/rc tags. -release = "0.12.6" +release = "0.12.10" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/custom_heuristics.rst new/cachecontrol-0.12.10/docs/custom_heuristics.rst --- old/cachecontrol-0.12.6/docs/custom_heuristics.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/custom_heuristics.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + =========================== Custom Caching Strategies =========================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/etags.rst new/cachecontrol-0.12.10/docs/etags.rst --- old/cachecontrol-0.12.6/docs/etags.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/etags.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + ============== ETag Support ============== @@ -5,8 +10,8 @@ CacheControl's support of ETags is slightly different than httplib2. In httplib2, an ETag is considered when using a cached response when the cache is considered stale. When a cached response is -expired and it has an ETag header, it returns a response with the -appropriate `If-None-Match` header. We'll call this behavior a **Time +expired and it has an ETag header, httplib2 issues the next request with +the appropriate `If-None-Match` header. We'll call this behavior a **Time Priority** cache as the ETag support only takes effect when the time has expired. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/index.rst new/cachecontrol-0.12.10/docs/index.rst --- old/cachecontrol-0.12.6/docs/index.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/index.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + .. CacheControl documentation master file, created by sphinx-quickstart on Mon Nov 4 15:01:23 2013. You can adapt this file completely to your liking, but it should at least @@ -67,7 +72,7 @@ If you give it a try, please let me know of any issues. -.. _httplib2: http://code.google.com/p/httplib2/ +.. _httplib2: https://github.com/httplib2/httplib2 .. _requests: http://docs.python-requests.org/ .. _Editing the Web: http://www.w3.org/1999/04/Editing/ .. _PyPI: https://pypi.python.org/pypi/CacheControl/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/release_notes.rst new/cachecontrol-0.12.10/docs/release_notes.rst --- old/cachecontrol-0.12.6/docs/release_notes.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/release_notes.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,7 +1,18 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + =============== Release Notes =============== +0.13.0 +====== + +* Dropped support for Python 2.7, 3.4, 3.5. +* Reduced memory usage when caching large files. + 0.12.0 ====== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/storage.rst new/cachecontrol-0.12.10/docs/storage.rst --- old/cachecontrol-0.12.6/docs/storage.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/storage.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + ==================== Storing Cache Data ==================== @@ -105,7 +110,7 @@ -.. _httplib2: http://code.google.com/p/httplib2/ +.. _httplib2: https://github.com/httplib2/httplib2 .. _lockfile: https://github.com/smontanaro/pylockfile .. _requests 2.1: http://docs.python-requests.org/en/latest/community/updates/#id2 .. _redis: https://github.com/andymccurdy/redis-py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/tips.rst new/cachecontrol-0.12.10/docs/tips.rst --- old/cachecontrol-0.12.6/docs/tips.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/tips.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + ========================= Tips and Best Practices ========================= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/docs/usage.rst new/cachecontrol-0.12.10/docs/usage.rst --- old/cachecontrol-0.12.6/docs/usage.rst 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/docs/usage.rst 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,8 @@ +.. + SPDX-FileCopyrightText: SPDX-FileCopyrightText: 2015 Eric Larson + + SPDX-License-Identifier: Apache-2.0 + ==================== Using CacheControl ==================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/examples/benchmark.py new/cachecontrol-0.12.10/examples/benchmark.py --- old/cachecontrol-0.12.6/examples/benchmark.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/examples/benchmark.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import sys import requests import argparse @@ -34,7 +38,7 @@ proc.start() start = datetime.now() - for i in xrange(0, 1000): + for i in range(0, 1000): sess.get(URL) sys.stdout.write(".") end = datetime.now() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/setup.cfg new/cachecontrol-0.12.10/setup.cfg --- old/cachecontrol-0.12.6/setup.cfg 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/setup.cfg 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,11 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + +[metadata] +license_files = + LICENSE.txt + [tool:pytest] norecursedirs = bin lib include build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/setup.py new/cachecontrol-0.12.10/setup.py --- old/cachecontrol-0.12.6/setup.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/setup.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,8 +1,12 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import setuptools long_description = open("README.rst").read() -VERSION = "0.12.6" +VERSION = "0.12.10" setup_params = dict( name="CacheControl", @@ -20,18 +24,17 @@ install_requires=["requests", "msgpack>=0.5.2"], extras_require={"filecache": ["lockfile>=0.9"], "redis": ["redis>=2.10.5"]}, entry_points={"console_scripts": ["doesitcache = cachecontrol._cmd:main"]}, - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", + python_requires=">=3.6", classifiers=[ "Development Status :: 4 - Beta", "Environment :: Web Environment", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Internet :: WWW/HTTP", ], ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/conftest.py new/cachecontrol-0.12.10/tests/conftest.py --- old/cachecontrol-0.12.6/tests/conftest.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/conftest.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + from pprint import pformat import os @@ -69,6 +73,11 @@ start_response("200 OK", headers) return [pformat(env).encode("utf8")] + def cache_60(self, env, start_response): + headers = [("Cache-Control", "public, max-age=60")] + start_response("200 OK", headers) + return [pformat(env).encode("utf8")] + def no_cache(self, env, start_response): headers = [("Cache-Control", "no-cache")] start_response("200 OK", headers) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/issue_263.py new/cachecontrol-0.12.10/tests/issue_263.py --- old/cachecontrol-0.12.6/tests/issue_263.py 1970-01-01 01:00:00.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/issue_263.py 2021-11-05 18:07:09.000000000 +0100 @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +import sys + +import cachecontrol +import requests +from cachecontrol.cache import DictCache +from cachecontrol.heuristics import BaseHeuristic + +import logging + +clogger = logging.getLogger("cachecontrol") +clogger.addHandler(logging.StreamHandler()) +clogger.setLevel(logging.DEBUG) + + +from pprint import pprint + + +class NoAgeHeuristic(BaseHeuristic): + def update_headers(self, response): + if "cache-control" in response.headers: + del response.headers["cache-control"] + + +cache_adapter = cachecontrol.CacheControlAdapter( + DictCache(), cache_etags=True, heuristic=NoAgeHeuristic() +) + + +session = requests.Session() +session.mount("https://", cache_adapter) + + +def log_resp(resp): + return + + print(f"{resp.status_code} {resp.request.method}") + for k, v in response.headers.items(): + print(f"{k}: {v}") + + +for i in range(2): + response = session.get( + "https://api.github.com/repos/sigmavirus24/github3.py/pulls/1033" + ) + log_resp(response) + print(f"Content length: {len(response.content)}") + print(response.from_cache) + if len(response.content) == 0: + sys.exit(1) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_adapter.py new/cachecontrol-0.12.10/tests/test_adapter.py --- old/cachecontrol-0.12.6/tests/test_adapter.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_adapter.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import mock import pytest @@ -45,6 +49,11 @@ sess.get(url) assert not r2.from_cache + def test_patch_invalidates_cache(self, url, sess): + r2 = sess.patch(url, data={"foo": "bar"}) + sess.get(url) + assert not r2.from_cache + def test_delete_invalidates_cache(self, url, sess): r2 = sess.delete(url) sess.get(url) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_cache_control.py new/cachecontrol-0.12.10/tests/test_cache_control.py --- old/cachecontrol-0.12.6/tests/test_cache_control.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_cache_control.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + """ Unit tests that verify our caching methods work correctly. """ @@ -67,7 +71,7 @@ # When the body is the wrong size, then we don't want to cache it # because it is obviously broken. resp = self.resp({"cache-control": "max-age=3600", "Content-Length": "5"}) - cc.cache_response(self.req(), resp, body=b"0" * 10) + cc.cache_response(self.req(), resp, b"0" * 10) assert not cc.cache.set.called @@ -82,8 +86,8 @@ resp = self.resp({"cache-control": "max-age=3600", "date": now}) req = self.req() cc.cache_response(req, resp) - cc.serializer.dumps.assert_called_with(req, resp, body=None) - cc.cache.set.assert_called_with(self.url, ANY) + cc.serializer.dumps.assert_called_with(req, resp, None) + cc.cache.set.assert_called_with(self.url, ANY, expires=3600) def test_cache_response_cache_max_age_with_invalid_value_not_cached(self, cc): now = time.strftime(TIME_FMT, time.gmtime()) @@ -133,7 +137,7 @@ # skip our in/out processing cc.serializer = Mock() cc.serializer.loads.return_value = cached_resp - cc.cache_url = Mock(return_value="http://foo.com") + cc.cache_url = Mock(return_value=self.url) result = cc.update_cached_response(Mock(), resp) @@ -152,7 +156,7 @@ return self.c.cached_request(mock_request) def test_cache_request_no_headers(self): - cached_resp = Mock(headers={"ETag": "jfd9094r808", "Content-Length": 100}) + cached_resp = Mock(headers={"ETag": "jfd9094r808", "Content-Length": 100}, status=200) self.c.cache = DictCache({self.url: cached_resp}) resp = self.req({}) assert not resp @@ -179,7 +183,7 @@ def test_cache_request_fresh_max_age(self): now = time.strftime(TIME_FMT, time.gmtime()) - resp = Mock(headers={"cache-control": "max-age=3600", "date": now}) + resp = Mock(headers={"cache-control": "max-age=3600", "date": now}, status=200) cache = DictCache({self.url: resp}) self.c.cache = cache @@ -189,7 +193,7 @@ def test_cache_request_unfresh_max_age(self): earlier = time.time() - 3700 # epoch - 1h01m40s now = time.strftime(TIME_FMT, time.gmtime(earlier)) - resp = Mock(headers={"cache-control": "max-age=3600", "date": now}) + resp = Mock(headers={"cache-control": "max-age=3600", "date": now}, status=200) self.c.cache = DictCache({self.url: resp}) r = self.req({}) assert not r @@ -198,7 +202,7 @@ later = time.time() + 86400 # GMT + 1 day expires = time.strftime(TIME_FMT, time.gmtime(later)) now = time.strftime(TIME_FMT, time.gmtime()) - resp = Mock(headers={"expires": expires, "date": now}) + resp = Mock(headers={"expires": expires, "date": now}, status=200) cache = DictCache({self.url: resp}) self.c.cache = cache r = self.req({}) @@ -208,7 +212,7 @@ sooner = time.time() - 86400 # GMT - 1 day expires = time.strftime(TIME_FMT, time.gmtime(sooner)) now = time.strftime(TIME_FMT, time.gmtime()) - resp = Mock(headers={"expires": expires, "date": now}) + resp = Mock(headers={"expires": expires, "date": now}, status=200) cache = DictCache({self.url: resp}) self.c.cache = cache r = self.req({}) @@ -217,7 +221,7 @@ def test_cached_request_with_bad_max_age_headers_not_returned(self): now = time.strftime(TIME_FMT, time.gmtime()) # Not a valid header; this would be from a misconfigured server - resp = Mock(headers={"cache-control": "max-age=xxx", "date": now}) + resp = Mock(headers={"cache-control": "max-age=xxx", "date": now}, status=200) self.c.cache = DictCache({self.url: resp}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_chunked_response.py new/cachecontrol-0.12.10/tests/test_chunked_response.py --- old/cachecontrol-0.12.6/tests/test_chunked_response.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_chunked_response.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 """ Test for supporting streamed responses (Transfer-Encoding: chunked) """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_etag.py new/cachecontrol-0.12.10/tests/test_etag.py --- old/cachecontrol-0.12.6/tests/test_etag.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_etag.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import pytest from mock import Mock, patch diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_expires_heuristics.py new/cachecontrol-0.12.10/tests/test_expires_heuristics.py --- old/cachecontrol-0.12.6/tests/test_expires_heuristics.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_expires_heuristics.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import calendar import time diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_max_age.py new/cachecontrol-0.12.10/tests/test_max_age.py --- old/cachecontrol-0.12.6/tests/test_max_age.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_max_age.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + from __future__ import print_function import pytest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_redirects.py new/cachecontrol-0.12.10/tests/test_redirects.py --- old/cachecontrol-0.12.6/tests/test_redirects.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_redirects.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + """ Test for supporting redirect caches as needed. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_regressions.py new/cachecontrol-0.12.10/tests/test_regressions.py --- old/cachecontrol-0.12.6/tests/test_regressions.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_regressions.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import sys import pytest @@ -13,10 +17,11 @@ @pytest.mark.skipif( sys.version.startswith("2"), reason="Only run this for python 3.x" ) - def test_file_cache_recognizes_consumed_file_handle(self): + def test_file_cache_recognizes_consumed_file_handle(self, url): s = CacheControl(Session(), FileCache("web_cache")) - s.get("http://httpbin.org/cache/60") - r = s.get("http://httpbin.org/cache/60") + the_url = url + "cache_60" + s.get(the_url) + r = s.get(the_url) assert r.from_cache s.close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_serialization.py new/cachecontrol-0.12.10/tests/test_serialization.py --- old/cachecontrol-0.12.6/tests/test_serialization.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_serialization.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import msgpack import requests @@ -8,7 +12,6 @@ class TestSerializer(object): - def setup(self): self.serializer = Serializer() self.response_data = { @@ -89,7 +92,9 @@ original_resp = requests.get(url, stream=True) req = original_resp.request - resp = self.serializer.loads(req, self.serializer.dumps(req, original_resp.raw)) + resp = self.serializer.loads( + req, self.serializer.dumps(req, original_resp.raw, original_resp.content) + ) assert resp.read() @@ -99,7 +104,7 @@ req = original_resp.request resp = self.serializer.loads( - req, self.serializer.dumps(req, original_resp.raw, body=data) + req, self.serializer.dumps(req, original_resp.raw, data) ) assert resp.read() == data @@ -114,5 +119,19 @@ original_resp.raw.headers["vary"] = "Foo" assert self.serializer.loads( - req, self.serializer.dumps(req, original_resp.raw, body=data) + req, self.serializer.dumps(req, original_resp.raw, data) ) + + def test_no_body_creates_response_file_handle_on_dumps(self, url): + original_resp = requests.get(url, stream=True) + data = None + req = original_resp.request + + assert self.serializer.loads( + req, self.serializer.dumps(req, original_resp.raw, data) + ) + + # By passing in data=None it will force a read of the file + # handle. Reading it again proves we're resetting the internal + # file handle with a buffer. + assert original_resp.raw.read() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_server_http_version.py new/cachecontrol-0.12.10/tests/test_server_http_version.py --- old/cachecontrol-0.12.6/tests/test_server_http_version.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_server_http_version.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import requests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_storage_filecache.py new/cachecontrol-0.12.10/tests/test_storage_filecache.py --- old/cachecontrol-0.12.6/tests/test_storage_filecache.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_storage_filecache.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + """ Unit tests that verify FileCache storage works correctly. """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_storage_redis.py new/cachecontrol-0.12.10/tests/test_storage_redis.py --- old/cachecontrol-0.12.6/tests/test_storage_redis.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_storage_redis.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + from datetime import datetime from mock import Mock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_stream.py new/cachecontrol-0.12.10/tests/test_stream.py --- old/cachecontrol-0.12.6/tests/test_stream.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_stream.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ -""" -Test for supporting streamed responses (Transfer-Encoding: chunked) -""" -import requests - -from cachecontrol import CacheControl - - -class TestStream(object): - - def setup(self): - self.sess = CacheControl(requests.Session()) - - def test_stream_is_cached(self, url): - resp_1 = self.sess.get(url + "stream") - content_1 = resp_1.content - - resp_2 = self.sess.get(url + "stream") - content_2 = resp_1.content - - assert not resp_1.from_cache - assert resp_2.from_cache - assert content_1 == content_2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tests/test_vary.py new/cachecontrol-0.12.10/tests/test_vary.py --- old/cachecontrol-0.12.6/tests/test_vary.py 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tests/test_vary.py 2021-11-05 18:07:09.000000000 +0100 @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2015 Eric Larson +# +# SPDX-License-Identifier: Apache-2.0 + import pytest import requests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cachecontrol-0.12.6/tox.ini new/cachecontrol-0.12.10/tox.ini --- old/cachecontrol-0.12.6/tox.ini 2019-12-22 18:43:35.000000000 +0100 +++ new/cachecontrol-0.12.10/tox.ini 2021-11-05 18:07:09.000000000 +0100 @@ -1,5 +1,17 @@ +; SPDX-FileCopyrightText: 2015 Eric Larson +; +; SPDX-License-Identifier: Apache-2.0 + [tox] -envlist = py27, py34, py35, py36, py37 +envlist = py27, py36, py37, py38, py39 + +[gh-actions] +python = + 2.7: py27 + 3.6: py36 + 3.7: py37 + 3.8: py38 + 3.9: py39 [testenv] deps = pytest