Skip to content

Commit

Permalink
fix!: drop support for Python 2.7 / 3.5 (#212)
Browse files Browse the repository at this point in the history
Drop 'six' module

Drop 'u"' prefixes for text

Remove other Python 2.7 workarounds

Drop use of 'pytz'

Dxpand range to allow 'google-auth' 2.x versions

Remove 'general_helpers.wraps': except for a backward-compatibility
import, 'functools.wraps' does everything wee need on Python >= 3.6.

Remove 'packaging' dependency

Release-As: 2.0.0b1

Closes #74.

Closes #215.
  • Loading branch information
tseaver committed Aug 3, 2021
1 parent ff6ef1b commit a30f004
Show file tree
Hide file tree
Showing 35 changed files with 191 additions and 349 deletions.
34 changes: 4 additions & 30 deletions CONTRIBUTING.rst
@@ -1,4 +1,3 @@
.. Generated by synthtool. DO NOT EDIT!
############
Contributing
############
Expand All @@ -22,7 +21,7 @@ In order to add a feature:
documentation.

- The feature must work fully on the following CPython versions:
2.7, 3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows.
3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows.

- The feature must not add unnecessary dependencies (where
"unnecessary" is of course subjective, but new dependencies should
Expand Down Expand Up @@ -77,8 +76,8 @@ We use `nox <https://nox.readthedocs.io/en/latest/>`__ to instrument our tests.

.. note::

The unit tests and system tests are described in the
``noxfile.py`` files in each directory.
The unit tests tests are described in the ``noxfile.py`` files
in each directory.

.. nox: https://pypi.org/project/nox/
Expand Down Expand Up @@ -133,29 +132,6 @@ Exceptions to PEP8:
"Function-Under-Test"), which is PEP8-incompliant, but more readable.
Some also use a local variable, ``MUT`` (short for "Module-Under-Test").

********************
Running System Tests
********************

- To run system tests, you can execute::

# Run all system tests
$ nox -s system

# Run a single system test
$ nox -s system-3.8 -- -k <name of test>


.. note::

System tests are only configured to run under Python 2.7 and 3.8.
For expediency, we do not run them in older versions of Python 3.

This alone will not run the tests. You'll need to change some local
auth settings and change some configuration in your project to
run all the tests.

- System tests will be run against an actual project. You should use local credentials from gcloud when possible. See `Best practices for application authentication <https://cloud.google.com/docs/authentication/best-practices-applications#local_development_and_testing_with_the>`__. Some tests require a service account. For those tests see `Authenticating as a service account <https://cloud.google.com/docs/authentication/production>`__.

*************
Test Coverage
Expand Down Expand Up @@ -221,13 +197,11 @@ Supported Python Versions

We support:

- `Python 2.7`_
- `Python 3.6`_
- `Python 3.7`_
- `Python 3.8`_
- `Python 3.9`_

.. _Python 2.7: https://docs.python.org/2.7/
.. _Python 3.6: https://docs.python.org/3.6/
.. _Python 3.7: https://docs.python.org/3.7/
.. _Python 3.8: https://docs.python.org/3.8/
Expand All @@ -239,7 +213,7 @@ Supported versions can be found in our ``noxfile.py`` `config`_.
.. _config: https://github.com/googleapis/python-api-core/blob/master/noxfile.py


We also explicitly decided to support Python 3 beginning with version 2.7.
We also explicitly decided to support Python 3 beginning with version 3.6.
Reasons for this include:

- Encouraging use of newest versions of Python 3
Expand Down
15 changes: 10 additions & 5 deletions README.rst
@@ -1,7 +1,7 @@
Core Library for Google Client Libraries
========================================

|pypi| |versions|
|pypi| |versions|

This library is not meant to stand-alone. Instead it defines
common helpers used by all Google API clients. For more information, see the
Expand All @@ -16,8 +16,13 @@ common helpers used by all Google API clients. For more information, see the

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.

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-api_core==1.31.1`.
19 changes: 0 additions & 19 deletions docs/auth.rst
Expand Up @@ -103,25 +103,6 @@ After creation, you can pass it directly to a :class:`Client <google.cloud.clien

.. _google-auth-guide: https://googleapis.dev/python/google-auth/latest/user-guide.html#service-account-private-key-files


Google App Engine Standard First Generation Environment
-------------------------------------------------------

These credentials are used only in the legacy Python 2.7
`First Generation Standard Environment`_. All other App Engine
runtimes use Compute Engine credentials.

.. _First Generation Standard Environment: https://cloud.google.com/appengine/docs/standard/runtimes

To create
:class:`credentials <google.auth.app_engine.Credentials>`
just for Google App Engine:

.. code:: python
from google.auth import app_engine
credentials = app_engine.Credentials()
Google Compute Engine Environment
---------------------------------

Expand Down
10 changes: 5 additions & 5 deletions google/api_core/bidi.py
Expand Up @@ -17,11 +17,10 @@
import collections
import datetime
import logging
import queue as queue_module
import threading
import time

from six.moves import queue

from google.api_core import exceptions

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -71,7 +70,7 @@ class _RequestQueueGenerator(object):
CPU consumed by spinning is pretty minuscule.
Args:
queue (queue.Queue): The request queue.
queue (queue_module.Queue): The request queue.
period (float): The number of seconds to wait for items from the queue
before checking if the RPC is cancelled. In practice, this
determines the maximum amount of time the request consumption
Expand Down Expand Up @@ -108,7 +107,7 @@ def __iter__(self):
while True:
try:
item = self._queue.get(timeout=self._period)
except queue.Empty:
except queue_module.Empty:
if not self._is_active():
_LOGGER.debug(
"Empty queue and inactive call, exiting request " "generator."
Expand Down Expand Up @@ -247,7 +246,7 @@ def __init__(self, start_rpc, initial_request=None, metadata=None):
self._start_rpc = start_rpc
self._initial_request = initial_request
self._rpc_metadata = metadata
self._request_queue = queue.Queue()
self._request_queue = queue_module.Queue()
self._request_generator = None
self._is_active = False
self._callbacks = []
Expand Down Expand Up @@ -645,6 +644,7 @@ def _thread_main(self, ready):
# Keeping the lock throughout avoids that.
# In the future, we could use `Condition.wait_for` if we drop
# Python 2.7.
# See: https://github.com/googleapis/python-api-core/issues/211
with self._wake:
while self._paused:
_LOGGER.debug("paused, waiting for waking.")
Expand Down
2 changes: 1 addition & 1 deletion google/api_core/client_info.py
Expand Up @@ -42,7 +42,7 @@ class ClientInfo(object):
Args:
python_version (str): The Python interpreter version, for example,
``'2.7.13'``.
``'3.9.6'``.
grpc_version (Optional[str]): The gRPC library version.
api_core_version (str): The google-api-core library version.
gapic_version (Optional[str]): The sversion of gapic-generated client
Expand Down
2 changes: 1 addition & 1 deletion google/api_core/client_options.py
Expand Up @@ -101,7 +101,7 @@ def from_dict(options):
"""Construct a client options object from a mapping object.
Args:
options (six.moves.collections_abc.Mapping): A mapping object with client options.
options (collections.abc.Mapping): A mapping object with client options.
See the docstring for ClientOptions for details on valid arguments.
"""

Expand Down
20 changes: 11 additions & 9 deletions google/api_core/datetime_helpers.py
Expand Up @@ -18,12 +18,10 @@
import datetime
import re

import pytz

from google.protobuf import timestamp_pb2


_UTC_EPOCH = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
_UTC_EPOCH = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
_RFC3339_MICROS = "%Y-%m-%dT%H:%M:%S.%fZ"
_RFC3339_NO_FRACTION = "%Y-%m-%dT%H:%M:%S"
# datetime.strptime cannot handle nanosecond precision: parse w/ regex
Expand Down Expand Up @@ -83,9 +81,9 @@ def to_microseconds(value):
int: Microseconds since the unix epoch.
"""
if not value.tzinfo:
value = value.replace(tzinfo=pytz.utc)
value = value.replace(tzinfo=datetime.timezone.utc)
# Regardless of what timezone is on the value, convert it to UTC.
value = value.astimezone(pytz.utc)
value = value.astimezone(datetime.timezone.utc)
# Convert the datetime to a microsecond timestamp.
return int(calendar.timegm(value.timetuple()) * 1e6) + value.microsecond

Expand Down Expand Up @@ -156,7 +154,7 @@ def from_rfc3339(value):
nanos = int(fraction) * (10 ** scale)
micros = nanos // 1000

return bare_seconds.replace(microsecond=micros, tzinfo=pytz.utc)
return bare_seconds.replace(microsecond=micros, tzinfo=datetime.timezone.utc)


from_rfc3339_nanos = from_rfc3339 # from_rfc3339_nanos method was deprecated.
Expand Down Expand Up @@ -256,7 +254,7 @@ def from_rfc3339(cls, stamp):
bare.minute,
bare.second,
nanosecond=nanos,
tzinfo=pytz.UTC,
tzinfo=datetime.timezone.utc,
)

def timestamp_pb(self):
Expand All @@ -265,7 +263,11 @@ def timestamp_pb(self):
Returns:
(:class:`~google.protobuf.timestamp_pb2.Timestamp`): Timestamp message
"""
inst = self if self.tzinfo is not None else self.replace(tzinfo=pytz.UTC)
inst = (
self
if self.tzinfo is not None
else self.replace(tzinfo=datetime.timezone.utc)
)
delta = inst - _UTC_EPOCH
seconds = int(delta.total_seconds())
nanos = self._nanosecond or self.microsecond * 1000
Expand All @@ -292,5 +294,5 @@ def from_timestamp_pb(cls, stamp):
bare.minute,
bare.second,
nanosecond=stamp.nanos,
tzinfo=pytz.UTC,
tzinfo=datetime.timezone.utc,
)

0 comments on commit a30f004

Please sign in to comment.