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
1720import datetime
1821import enum
19- import functools
20- from importlib import metadata
21- import logging
2222import sys
2323import textwrap
24- from typing import Any , Dict , List , NamedTuple , Optional , Tuple
24+ from typing import Dict , List , NamedTuple , Optional , Tuple
2525import warnings
2626
27- _LOGGER = logging .getLogger (__name__ )
28-
2927
3028class 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
5950class 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
7260PYTHON_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)
132112DEPRECATION_WARNING_PERIOD = datetime .timedelta (days = 365 )
133113EOL_GRACE_PERIOD = datetime .timedelta (weeks = 1 )
114+ _PACKAGE_LABEL = 'package firebase-admin (firebase_admin)'
134115
135116
136117def _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-
178122def 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