Skip to content

Commit f80ea07

Browse files
committed
feat(core): warn when importing on Python 3.10.
Emit a FutureWarning at import time when running on Python < 3.11 using a fixed per-release version tuple rather than a runtime calendar check.
1 parent 00e0754 commit f80ea07

4 files changed

Lines changed: 106 additions & 4 deletions

File tree

‎README.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,11 @@ requests, code review feedback, and also pull requests.
4343

4444
## Supported Python Versions
4545

46-
We currently support Python 3.10+. However, Python 3.10 support is deprecated,
47-
and developers are strongly advised to use Python 3.11 or higher. Firebase
48-
Admin Python SDK is also tested on PyPy and
49-
[Google App Engine](https://cloud.google.com/appengine/) environments.
46+
We currently support Python 3.10+. However, Python 3.10 support is deprecated
47+
and will be dropped in an upcoming minor release. Developers are strongly
48+
advised to use Python 3.11 or higher. Firebase Admin Python SDK is also tested
49+
on PyPy and [Google App Engine](https://cloud.google.com/appengine/)
50+
environments.
5051

5152

5253
## Documentation

‎firebase_admin/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@
2121
from google.auth.credentials import Credentials as GoogleAuthCredentials
2222
from google.auth.exceptions import DefaultCredentialsError
2323
from firebase_admin import credentials
24+
from firebase_admin import _python_version_support
2425
from firebase_admin.__about__ import __version__
2526

2627

28+
# Perform Python version check and emit a support warning if needed.
29+
_python_version_support.check_python_version()
30+
31+
2732
_apps = {}
2833
_apps_lock = threading.RLock()
2934
_clock = datetime.datetime.utcnow
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Copyright 2026 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Runtime Python version deprecation check for the Firebase Admin SDK."""
16+
17+
import sys
18+
import warnings
19+
20+
# Minimum Python (major, minor) version that does not emit a deprecation warning.
21+
# Bump this tuple in a minor release to deprecate an older Python version ahead
22+
# of dropping it in a future release.
23+
_MIN_NON_DEPRECATED_VERSION = (3, 11)
24+
25+
26+
def check_python_version() -> None:
27+
"""Emits a FutureWarning if the running Python version is deprecated."""
28+
current = (sys.version_info.major, sys.version_info.minor)
29+
if current < _MIN_NON_DEPRECATED_VERSION:
30+
current_str = f'{current[0]}.{current[1]}'
31+
recommended_str = (
32+
f'{_MIN_NON_DEPRECATED_VERSION[0]}.{_MIN_NON_DEPRECATED_VERSION[1]}'
33+
)
34+
warnings.warn(
35+
f'Support for Python {current_str} in firebase-admin is deprecated '
36+
'and will be dropped in a future minor release. Please upgrade to '
37+
f'Python {recommended_str} or higher to continue receiving updates.',
38+
FutureWarning,
39+
stacklevel=2,
40+
)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright 2026 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Tests for firebase_admin._python_version_support."""
16+
17+
from collections import namedtuple
18+
from unittest.mock import patch
19+
import warnings
20+
21+
import pytest
22+
23+
from firebase_admin._python_version_support import check_python_version
24+
25+
_VersionInfo = namedtuple('_VersionInfo', ['major', 'minor'])
26+
27+
28+
@pytest.mark.parametrize('version_tuple', [(3, 9), (3, 10)])
29+
def test_deprecated_python_versions_emit_future_warning(version_tuple):
30+
mock_version = _VersionInfo(major=version_tuple[0], minor=version_tuple[1])
31+
version_str = f'{version_tuple[0]}.{version_tuple[1]}'
32+
33+
with patch('firebase_admin._python_version_support.sys.version_info', mock_version):
34+
with pytest.warns(FutureWarning) as record:
35+
check_python_version()
36+
37+
assert len(record) == 1
38+
assert record[0].filename == __file__
39+
expected = (
40+
f'Support for Python {version_str} in firebase-admin is deprecated '
41+
'and will be dropped in a future minor release. Please upgrade to '
42+
'Python 3.11 or higher to continue receiving updates.'
43+
)
44+
assert str(record[0].message) == expected
45+
46+
47+
@pytest.mark.parametrize('version_tuple', [(3, 11), (3, 12), (3, 13), (3, 14), (3, 15)])
48+
def test_supported_python_versions_do_not_warn(version_tuple):
49+
mock_version = _VersionInfo(major=version_tuple[0], minor=version_tuple[1])
50+
51+
with patch('firebase_admin._python_version_support.sys.version_info', mock_version):
52+
with warnings.catch_warnings(record=True) as recorded:
53+
warnings.simplefilter('always')
54+
check_python_version()
55+
56+
assert not recorded

0 commit comments

Comments
 (0)