Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: drop Python 2.7 support #229

Merged
merged 20 commits into from Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 9 additions & 5 deletions README.rst
Expand Up @@ -16,15 +16,19 @@ support at `google._async_resumable_media`.

Supported Python Versions
-------------------------
Python >= 3.5
Python >= 3.6

Deprecated Python Versions
--------------------------
Python == 2.7. Python 2.7 support will be removed on January 1, 2020.
tseaver marked this conversation as resolved.
Show resolved Hide resolved
Unsupported Python Versions
---------------------------

Python == 2.7, Python == 3.5.

The last version of this library compatible with Python 2.7 and 3.5 is
`google-resumable-media==1.3.1`.

License
-------

Apache 2.0 - See `the LICENSE`_ for more information.

.. _the LICENSE: https://github.com/googleapis/google-resumable-media-python/blob/master/LICENSE
.. _the LICENSE: https://github.com/googleapis/google-resumable-media-python/blob/master/LICENSE
12 changes: 6 additions & 6 deletions google/_async_resumable_media/__init__.py
Expand Up @@ -52,10 +52,10 @@


__all__ = [
u"DataCorruption",
u"InvalidResponse",
u"PERMANENT_REDIRECT",
u"RetryStrategy",
u"TOO_MANY_REQUESTS",
u"UPLOAD_CHUNK_SIZE",
"DataCorruption",
"InvalidResponse",
"PERMANENT_REDIRECT",
"RetryStrategy",
"TOO_MANY_REQUESTS",
"UPLOAD_CHUNK_SIZE",
tseaver marked this conversation as resolved.
Show resolved Hide resolved
]
61 changes: 29 additions & 32 deletions google/_async_resumable_media/_download.py
Expand Up @@ -14,12 +14,9 @@

"""Virtual bases classes for downloading media from Google APIs."""


import http.client
import re

from six.moves import http_client


from google._async_resumable_media import _helpers
from google.resumable_media import common

Expand All @@ -28,9 +25,9 @@
r"bytes (?P<start_byte>\d+)-(?P<end_byte>\d+)/(?P<total_bytes>\d+)",
flags=re.IGNORECASE,
)
_ACCEPTABLE_STATUS_CODES = (http_client.OK, http_client.PARTIAL_CONTENT)
_GET = u"GET"
_ZERO_CONTENT_RANGE_HEADER = u"bytes */0"
_ACCEPTABLE_STATUS_CODES = (http.client.OK, http.client.PARTIAL_CONTENT)
_GET = "GET"
_ZERO_CONTENT_RANGE_HEADER = "bytes */0"


class DownloadBase(object):
Expand Down Expand Up @@ -79,7 +76,7 @@ def _get_status_code(response):
Raises:
NotImplementedError: Always, since virtual.
"""
raise NotImplementedError(u"This implementation is virtual.")
raise NotImplementedError("This implementation is virtual.")

@staticmethod
def _get_headers(response):
Expand All @@ -91,7 +88,7 @@ def _get_headers(response):
Raises:
NotImplementedError: Always, since virtual.
"""
raise NotImplementedError(u"This implementation is virtual.")
raise NotImplementedError("This implementation is virtual.")

@staticmethod
def _get_body(response):
Expand All @@ -103,7 +100,7 @@ def _get_body(response):
Raises:
NotImplementedError: Always, since virtual.
"""
raise NotImplementedError(u"This implementation is virtual.")
raise NotImplementedError("This implementation is virtual.")


class Download(DownloadBase):
Expand Down Expand Up @@ -164,7 +161,7 @@ def _prepare_request(self):
.. _sans-I/O: https://sans-io.readthedocs.io/
"""
if self.finished:
raise ValueError(u"A download can only be used once.")
raise ValueError("A download can only be used once.")

add_bytes_range(self.start, self.end, self._headers)
return _GET, self.media_url, None, self._headers
Expand Down Expand Up @@ -205,7 +202,7 @@ def consume(self, transport, timeout=None):
Raises:
NotImplementedError: Always, since virtual.
"""
raise NotImplementedError(u"This implementation is virtual.")
raise NotImplementedError("This implementation is virtual.")


class ChunkedDownload(DownloadBase):
Expand Down Expand Up @@ -239,7 +236,7 @@ class ChunkedDownload(DownloadBase):
def __init__(self, media_url, chunk_size, stream, start=0, end=None, headers=None):
if start < 0:
raise ValueError(
u"On a chunked download the starting " u"value cannot be negative."
"On a chunked download the starting " "value cannot be negative."
)
super(ChunkedDownload, self).__init__(
media_url, stream=stream, start=start, end=end, headers=headers
Expand Down Expand Up @@ -312,9 +309,9 @@ def _prepare_request(self):
.. _sans-I/O: https://sans-io.readthedocs.io/
"""
if self.finished:
raise ValueError(u"Download has finished.")
raise ValueError("Download has finished.")
if self.invalid:
raise ValueError(u"Download is invalid and cannot be re-used.")
raise ValueError("Download is invalid and cannot be re-used.")

curr_start, curr_end = self._get_byte_range()
add_bytes_range(curr_start, curr_end, self._headers)
Expand Down Expand Up @@ -382,12 +379,12 @@ async def _process_response(self, response):
response, self._get_headers, callback=self._make_invalid
)

transfer_encoding = headers.get(u"transfer-encoding")
transfer_encoding = headers.get("transfer-encoding")

if transfer_encoding is None:
content_length = _helpers.header_required(
response,
u"content-length",
"content-length",
self._get_headers,
callback=self._make_invalid,
)
Expand All @@ -397,10 +394,10 @@ async def _process_response(self, response):
self._make_invalid()
raise common.InvalidResponse(
response,
u"Response is different size than content-length",
u"Expected",
"Response is different size than content-length",
"Expected",
num_bytes,
u"Received",
"Received",
len(response_body),
)
else:
Expand Down Expand Up @@ -434,7 +431,7 @@ def consume_next_chunk(self, transport, timeout=None):
Raises:
NotImplementedError: Always, since virtual.
"""
raise NotImplementedError(u"This implementation is virtual.")
raise NotImplementedError("This implementation is virtual.")


def add_bytes_range(start, end, headers):
Expand Down Expand Up @@ -474,18 +471,18 @@ def add_bytes_range(start, end, headers):
return
else:
# NOTE: This assumes ``end`` is non-negative.
bytes_range = u"0-{:d}".format(end)
bytes_range = "0-{:d}".format(end)
else:
if end is None:
if start < 0:
bytes_range = u"{:d}".format(start)
bytes_range = "{:d}".format(start)
else:
bytes_range = u"{:d}-".format(start)
bytes_range = "{:d}-".format(start)
else:
# NOTE: This is invalid if ``start < 0``.
bytes_range = u"{:d}-{:d}".format(start, end)
bytes_range = "{:d}-{:d}".format(start, end)

headers[_helpers.RANGE_HEADER] = u"bytes=" + bytes_range
headers[_helpers.RANGE_HEADER] = "bytes=" + bytes_range


def get_range_info(response, get_headers, callback=_helpers.do_nothing):
Expand Down Expand Up @@ -514,15 +511,15 @@ def get_range_info(response, get_headers, callback=_helpers.do_nothing):
callback()
raise common.InvalidResponse(
response,
u"Unexpected content-range header",
"Unexpected content-range header",
content_range,
u'Expected to be of the form "bytes {start}-{end}/{total}"',
'Expected to be of the form "bytes {start}-{end}/{total}"',
)

return (
int(match.group(u"start_byte")),
int(match.group(u"end_byte")),
int(match.group(u"total_bytes")),
int(match.group("start_byte")),
int(match.group("end_byte")),
int(match.group("total_bytes")),
)


Expand All @@ -541,7 +538,7 @@ def _check_for_zero_content_range(response, get_status_code, get_headers):
Returns:
bool: True if content range total bytes is zero, false otherwise.
"""
if get_status_code(response) == http_client.REQUESTED_RANGE_NOT_SATISFIABLE:
if get_status_code(response) == http.client.REQUESTED_RANGE_NOT_SATISFIABLE:
content_range = _helpers.header_required(
response,
_helpers.CONTENT_RANGE_HEADER,
Expand Down
14 changes: 7 additions & 7 deletions google/_async_resumable_media/_helpers.py
Expand Up @@ -22,16 +22,16 @@
from google.resumable_media import common


RANGE_HEADER = u"range"
CONTENT_RANGE_HEADER = u"content-range"
RANGE_HEADER = "range"
CONTENT_RANGE_HEADER = "content-range"

_SLOW_CRC32C_WARNING = (
"Currently using crcmod in pure python form. This is a slow "
"implementation. Python 3 has a faster implementation, `google-crc32c`, "
"which will be used if it is installed."
)
_HASH_HEADER = u"x-goog-hash"
_MISSING_CHECKSUM = u"""\
_HASH_HEADER = "x-goog-hash"
_MISSING_CHECKSUM = """\
No {checksum_type} checksum was returned from the service while downloading {}
(which happens for composite objects), so client-side content integrity
checking is not being performed."""
Expand Down Expand Up @@ -65,7 +65,7 @@ def header_required(response, name, get_headers, callback=do_nothing):
if name not in headers:
callback()
raise common.InvalidResponse(
response, u"Response headers must contain header", name
response, "Response headers must contain header", name
)

return headers[name]
Expand Down Expand Up @@ -94,9 +94,9 @@ def require_status_code(response, status_codes, get_status_code, callback=do_not
callback()
raise common.InvalidResponse(
response,
u"Request failed with status code",
"Request failed with status code",
status_code,
u"Expected one of",
"Expected one of",
*status_codes
)
return status_code
Expand Down