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

Reply via email to