Skip to content

Commit 45a5e29

Browse files
committed
fix(core): simplify Python version support check and fix EoL window
Remove dynamic package metadata lookup and unused GAPIC fields from VersionInfo, and start the EoL warning window on python_eol.
1 parent 85079d2 commit 45a5e29

3 files changed

Lines changed: 67 additions & 157 deletions

File tree

‎firebase_admin/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727

2828
# Perform Python version check and emit a support warning if needed.
29-
_python_version_support.check_python_version(package='firebase-admin')
29+
_python_version_support.check_python_version()
3030

3131

3232
_apps = {}

‎firebase_admin/_python_version_support.py‎

Lines changed: 27 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -12,98 +12,80 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
"""Code to check Python versions supported by the Firebase Admin Python SDK."""
15+
"""Code to check Python versions supported by the Firebase Admin Python SDK.
16+
17+
Adapted from ``google.api_core._python_version_support``.
18+
"""
1619

1720
import datetime
1821
import enum
19-
import functools
20-
from importlib import metadata
21-
import logging
2222
import sys
2323
import textwrap
24-
from typing import Any, Dict, List, NamedTuple, Optional, Tuple
24+
from typing import Dict, List, NamedTuple, Optional, Tuple
2525
import warnings
2626

27-
_LOGGER = logging.getLogger(__name__)
28-
2927

3028
class PythonVersionStatus(enum.Enum):
31-
"""Support status of a Python version in this client library artifact release.
32-
33-
"Support", in this context, means that this release of a client library
34-
artifact is configured to run on the currently configured version of
35-
Python.
36-
"""
37-
38-
PYTHON_VERSION_STATUS_UNSPECIFIED = 'PYTHON_VERSION_STATUS_UNSPECIFIED'
29+
"""Support status of a Python version in this SDK release."""
3930

4031
PYTHON_VERSION_SUPPORTED = 'PYTHON_VERSION_SUPPORTED'
41-
"""This Python version is fully supported, so the artifact running on this
32+
"""This Python version is fully supported, so the SDK running on this
4233
version will have all features and bug fixes."""
4334

4435
PYTHON_VERSION_DEPRECATED = 'PYTHON_VERSION_DEPRECATED'
4536
"""This Python version is still supported, but support will end within a
46-
year. At that time, there will be no more releases for this artifact
37+
year. At that time, there will be no more releases for this SDK
4738
running under this Python version."""
4839

4940
PYTHON_VERSION_EOL = 'PYTHON_VERSION_EOL'
5041
"""This Python version has reached its end of life in the Python community
51-
(see https://devguide.python.org/versions/), and this artifact will cease
42+
(see https://devguide.python.org/versions/), and this SDK will cease
5243
supporting this Python version within the next few releases."""
5344

5445
PYTHON_VERSION_UNSUPPORTED = 'PYTHON_VERSION_UNSUPPORTED'
55-
"""This release of the client library artifact may not be the latest, since
56-
current releases no longer support this Python version."""
46+
"""This release of the SDK may not be the latest, since current releases no
47+
longer support this Python version."""
5748

5849

5950
class VersionInfo(NamedTuple):
6051
"""Hold release and support date information for a Python version."""
6152

6253
version: str
63-
python_beta: Optional[datetime.date]
6454
python_start: datetime.date
6555
python_eol: datetime.date
66-
gapic_start: Optional[datetime.date] = None # unused
67-
gapic_deprecation: Optional[datetime.date] = None
68-
gapic_end: Optional[datetime.date] = None
69-
dep_unpatchable_cve: Optional[datetime.date] = None # unused
56+
deprecation_date: Optional[datetime.date] = None
57+
end_of_support_date: Optional[datetime.date] = None
7058

7159

7260
PYTHON_VERSIONS: List[VersionInfo] = [
7361
# Refer to https://devguide.python.org/versions/ and the PEPs linked therefrom.
7462
VersionInfo(
7563
version='3.9',
76-
python_beta=datetime.date(2020, 5, 18),
7764
python_start=datetime.date(2020, 10, 5),
7865
python_eol=datetime.date(2025, 10, 5),
7966
),
8067
VersionInfo(
8168
version='3.10',
82-
python_beta=datetime.date(2021, 5, 3),
8369
python_start=datetime.date(2021, 10, 4),
8470
python_eol=datetime.date(2026, 10, 4),
8571
),
8672
VersionInfo(
8773
version='3.11',
88-
python_beta=datetime.date(2022, 5, 8),
8974
python_start=datetime.date(2022, 10, 24),
9075
python_eol=datetime.date(2027, 10, 24),
9176
),
9277
VersionInfo(
9378
version='3.12',
94-
python_beta=datetime.date(2023, 5, 22),
9579
python_start=datetime.date(2023, 10, 2),
9680
python_eol=datetime.date(2028, 10, 2),
9781
),
9882
VersionInfo(
9983
version='3.13',
100-
python_beta=datetime.date(2024, 5, 8),
10184
python_start=datetime.date(2024, 10, 7),
10285
python_eol=datetime.date(2029, 10, 7),
10386
),
10487
VersionInfo(
10588
version='3.14',
106-
python_beta=datetime.date(2025, 5, 7),
10789
python_start=datetime.date(2025, 10, 7),
10890
python_eol=datetime.date(2030, 10, 7),
10991
),
@@ -118,70 +100,30 @@ class VersionInfo(NamedTuple):
118100
_FAKE_PAST_DATE = datetime.date.min + datetime.timedelta(days=900)
119101
_FAKE_PAST_VERSION = VersionInfo(
120102
version='0.0',
121-
python_beta=_FAKE_PAST_DATE,
122103
python_start=_FAKE_PAST_DATE,
123104
python_eol=_FAKE_PAST_DATE,
124105
)
125106
_FAKE_FUTURE_DATE = datetime.date.max - datetime.timedelta(days=900)
126107
_FAKE_FUTURE_VERSION = VersionInfo(
127108
version='999.0',
128-
python_beta=_FAKE_FUTURE_DATE,
129109
python_start=_FAKE_FUTURE_DATE,
130110
python_eol=_FAKE_FUTURE_DATE,
131111
)
132112
DEPRECATION_WARNING_PERIOD = datetime.timedelta(days=365)
133113
EOL_GRACE_PERIOD = datetime.timedelta(weeks=1)
114+
_PACKAGE_LABEL = 'package firebase-admin (firebase_admin)'
134115

135116

136117
def _flatten_message(text: str) -> str:
137118
"""Dedent a multi-line string and flatten it into a single line."""
138119
return ' '.join(textwrap.dedent(text).strip().split())
139120

140121

141-
@functools.cache
142-
def _cached_packages_distributions():
143-
# `importlib.metadata.packages_distributions()` is only available in Python 3.10+.
144-
packages_distributions = getattr(metadata, 'packages_distributions', None)
145-
if packages_distributions is None: # pragma: NO COVER
146-
return {}
147-
return packages_distributions()
148-
149-
150-
def _get_pypi_package_name(module_name: str) -> Optional[str]:
151-
"""Determine the PyPI package name for a given module name."""
152-
try:
153-
module_to_distributions = _cached_packages_distributions()
154-
155-
if module_name in module_to_distributions: # pragma: NO COVER
156-
return module_to_distributions[module_name][0]
157-
except Exception as err: # pragma: NO COVER # pylint: disable=broad-except
158-
_LOGGER.info(
159-
'An error occurred while determining PyPI package name for %s: %s',
160-
module_name,
161-
err,
162-
)
163-
164-
return None
165-
166-
167-
def _get_distribution_and_import_packages(import_package: str) -> Tuple[str, Any]:
168-
"""Return a pretty string with distribution & import package names."""
169-
distribution_package = _get_pypi_package_name(import_package)
170-
pretty_package_name = (
171-
f'package {distribution_package} ({import_package})'
172-
if distribution_package
173-
else import_package
174-
)
175-
return pretty_package_name, distribution_package
176-
177-
178122
def check_python_version(
179-
package: str = 'firebase-admin',
180123
today: Optional[datetime.date] = None) -> PythonVersionStatus:
181124
"""Check the running Python version and issue a support warning if needed.
182125
183126
Args:
184-
package: The name of the package to display in the warning message.
185127
today: The date to check against. Defaults to the current date.
186128
187129
Returns:
@@ -201,10 +143,12 @@ def check_python_version(
201143
else:
202144
version_info = _FAKE_FUTURE_VERSION
203145

204-
gapic_deprecation = version_info.gapic_deprecation or (
146+
deprecation_date = version_info.deprecation_date or (
205147
version_info.python_eol - DEPRECATION_WARNING_PERIOD
206148
)
207-
gapic_end = version_info.gapic_end or (version_info.python_eol + EOL_GRACE_PERIOD)
149+
end_of_support_date = version_info.end_of_support_date or (
150+
version_info.python_eol + EOL_GRACE_PERIOD
151+
)
208152

209153
def min_python(date: datetime.date) -> str:
210154
"""Find the minimum supported Python version for a given date."""
@@ -213,52 +157,42 @@ def min_python(date: datetime.date) -> str:
213157
return f'{version[0]}.{version[1]}'
214158
return 'at a currently supported version [https://devguide.python.org/versions]'
215159

216-
# Resolve the pretty package label lazily so we avoid any work on
217-
# the happy path (supported Python version, no warning needed).
218-
def get_package_label():
219-
label, _ = _get_distribution_and_import_packages(package)
220-
return label
221-
222-
if gapic_end < today:
223-
package_label = get_package_label()
160+
if end_of_support_date < today:
224161
message = _flatten_message(
225162
f"""
226163
You are using a non-supported Python version ({py_version_str}).
227-
Google will not post any further updates to {package_label}
164+
Google will not post any further updates to {_PACKAGE_LABEL}
228165
supporting this Python version. Please upgrade to the latest Python
229166
version, or at least Python {min_python(today)}, and then update
230-
{package_label}.
167+
{_PACKAGE_LABEL}.
231168
"""
232169
)
233170
warnings.warn(message, FutureWarning)
234171
return PythonVersionStatus.PYTHON_VERSION_UNSUPPORTED
235172

236-
eol_date = version_info.python_eol + EOL_GRACE_PERIOD
237-
if eol_date <= today <= gapic_end:
238-
package_label = get_package_label()
173+
if version_info.python_eol <= today <= end_of_support_date:
239174
message = _flatten_message(
240175
f"""
241176
You are using a Python version ({py_version_str})
242-
past its end of life. Google will update {package_label}
177+
past its end of life. Google will update {_PACKAGE_LABEL}
243178
with critical bug fixes on a best-effort basis, but not
244179
with any other fixes or features. Please upgrade
245180
to the latest Python version, or at least Python
246-
{min_python(today)}, and then update {package_label}.
181+
{min_python(today)}, and then update {_PACKAGE_LABEL}.
247182
"""
248183
)
249184
warnings.warn(message, FutureWarning)
250185
return PythonVersionStatus.PYTHON_VERSION_EOL
251186

252-
if gapic_deprecation <= today <= gapic_end:
253-
package_label = get_package_label()
187+
if deprecation_date <= today < version_info.python_eol:
254188
message = _flatten_message(
255189
f"""
256190
You are using a Python version ({py_version_str}) which Google will
257-
stop supporting in new releases of {package_label} once it reaches
191+
stop supporting in new releases of {_PACKAGE_LABEL} once it reaches
258192
its end of life ({version_info.python_eol}). Please upgrade to the
259193
latest Python version, or at least Python
260194
{min_python(version_info.python_eol)}, to continue receiving updates
261-
for {package_label} past that date.
195+
for {_PACKAGE_LABEL} past that date.
262196
"""
263197
)
264198
warnings.warn(message, FutureWarning)

0 commit comments

Comments
 (0)