-
Notifications
You must be signed in to change notification settings - Fork 95
feat: provide and use Python version support check #832
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
Merged
+915
−2
Merged
Changes from 1 commit
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
6316d70
feat: provide Python run-time version support
vchudnov-g a136ad7
feat: apply Python version suport warnings to api_core
vchudnov-g 45cd647
feat: add deprecation check for the protobuf package
vchudnov-g 25225fa
format files
vchudnov-g 1d567c0
fix lint warning
vchudnov-g f1dbbb4
add docstring to `warn_deprecation_for_versions_less_than`
vchudnov-g e3fd56f
Add/fix docstrings
vchudnov-g 8b1dfb1
fix typo
vchudnov-g 4b9208e
add test for _python_package_support.py
vchudnov-g 5cf8652
add constants for various buffer periods
vchudnov-g 7d8b1c7
Update warning code to only require import package names
vchudnov-g cda8e27
Fix messaegs and test
vchudnov-g db92fac
Add TODO: provide the functionality in previous versions of api_core
vchudnov-g 118a7c8
Fix mypy failures
vchudnov-g f1c46aa
Try to remove a round-off error causing a test mock failure
vchudnov-g 474ec0d
Remove more potential test failures/warnings
vchudnov-g 2083b49
Format
vchudnov-g 4ea124e
Try making the specified_timeout a float
vchudnov-g c5949c4
fix: tweak message parameter names
vchudnov-g 6fc1473
fix: add PYTHON_VERSION_STATUS_UNSPECIFIED enum value
vchudnov-g 8829e20
docs: tweak TODOs
vchudnov-g bdb6260
fix test to match code changes
vchudnov-g 7896664
fix: restore asyncio designator for async tests
vchudnov-g 54a5611
Remove some workarounds trying to fix presubmit errors (since fixed)
vchudnov-g 2e2990b
Additional test tweaks to prevent non-significant failures
vchudnov-g 35a2074
chore: fix test that was waiting before initiating operation
vchudnov-g cd64832
fix: skip coverage checks for code specific to Pyton 3.7
vchudnov-g e36414a
chore: try to address coverage failures
vchudnov-g b6245ca
chore: try to address more coverage failures
vchudnov-g 3a897ba
chore: fix comments and exported function
vchudnov-g 814ea63
fix lint
vchudnov-g 8dee04b
chore: fix unit test
vchudnov-g 95f4777
chore: lint
vchudnov-g a34ec15
Use warnings module instead of logging module
vchudnov-g a04e2e6
fix: print the current package versions correctly
vchudnov-g 8b3f337
wip: before gemini doc fixes
vchudnov-g 29896cf
fix: return tuple of version tuple and version string, fix tests
vchudnov-g d421f98
lint
vchudnov-g ac76f7a
feat: add grace period for 3.9; tweak warning
vchudnov-g e093a96
lint
vchudnov-g 187f848
allow providing a recommended version
vchudnov-g b575a16
refactor: used namedtuple
vchudnov-g ecb7211
refactor: s/"--"/UNKNOWN_VERSION_STRING/ in code, not test
vchudnov-g 3c587cf
refactor s/next_supported_version/minimum_fully_supported_version/
vchudnov-g fbe0f0b
refactor: s/dependent_/consumer_/
vchudnov-g 28b0b32
refactor: add _PACKAGE_DEPENDENCY_WARNINGS
vchudnov-g 21c9aec
refactor: reorder and comment on _init__ statements for clarity
vchudnov-g e24c13d
fix: exapnd VersionInfo with version field; clarify fake dates
vchudnov-g dbc3a26
doc: document PythonVersionSupportStatus
vchudnov-g d472bae
refactor: make fake past and future versions into constants
vchudnov-g 0550f83
refactor: reword default string for min_python
vchudnov-g 491b695
fix: fix populating PYTHON_VERSION_INFO
vchudnov-g 6338389
fix: type hints
vchudnov-g 05bcf6f
feat: allow check_dependency_versions() to take any number of Depende…
vchudnov-g fc224b7
add unit test to satisfy coverage requirement
vchudnov-g a6c40ce
fix lint
vchudnov-g d0414b2
fix lint
vchudnov-g 835df53
test: add test for _flatten_message
vchudnov-g File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add deprecation check for the protobuf package
- Loading branch information
commit 45cd64786e7562b954dede73ec29215d6be9f670
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| # Copyright 2025 Google LLC | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Code to check versions of dependencies used by Google Cloud Client Libraries.""" | ||
|
|
||
| import logging | ||
| import sys | ||
| from typing import Optional | ||
| from ._python_version_support import _flatten_message | ||
|
|
||
| # It is a good practice to alias the Version class for clarity in type hints. | ||
| from packaging.version import parse as parse_version, Version as PackagingVersion | ||
|
|
||
|
|
||
| def get_dependency_version(dependency_name: str) -> Optional[PackagingVersion]: | ||
| """Get the parsed version of an installed package dependency. | ||
|
|
||
| This function checks for an installed package and returns its version | ||
| as a `packaging.version.Version` object for safe comparison. It handles | ||
| both modern (Python 3.8+) and legacy (Python 3.7) environments. | ||
|
|
||
| Args: | ||
| dependency_name: The distribution name of the package (e.g., 'requests'). | ||
|
|
||
| Returns: | ||
| A `packaging.version.Version` object, or `None` if the package | ||
| is not found or another error occurs during version discovery. | ||
| """ | ||
| try: | ||
| if sys.version_info >= (3, 8): | ||
| from importlib import metadata | ||
| version_string = metadata.version(dependency_name) | ||
| return parse_version(version_string) | ||
|
|
||
| # TODO: Remove this code path once we drop support for Python 3.7 | ||
| else: | ||
| # Use pkg_resources, which is part of setuptools. | ||
| import pkg_resources | ||
| version_string = pkg_resources.get_distribution(dependency_name).version | ||
| return parse_version(version_string) | ||
|
|
||
| except: | ||
| return None | ||
|
|
||
|
|
||
| def warn_deprecation_for_versions_less_than(dependent_package:str, | ||
| dependency_name:str, | ||
| next_supported_version:str, | ||
| message_template: Optional[str] = None): | ||
| if not dependent_package or not dependency_name or not next_supported_version: | ||
| return | ||
| version_used = get_dependency_version(dependency_name) | ||
| if not version_used: | ||
| return | ||
| if version_used < parse_version(next_supported_version): | ||
| message_template = message_template or _flatten_message( | ||
| """DEPRECATION: Package {dependent_package} depends on | ||
| {dependency_name}, currently installed at version | ||
| {version_used.__str__}. Future updates to | ||
| {dependent_package} will require {dependency_name} at | ||
| version {next_supported_version} or higher. Please ensure | ||
| that either (a) your Python environment doesn't pin the | ||
| version of {dependency_name}, so that updates to | ||
| {dependent_package} can require the higher version, or (b) | ||
| you manually update your Python environment to use at | ||
| least version {next_supported_version} of | ||
| {dependency_name}.""" | ||
| ) | ||
| logging.warning( | ||
| message_template.format( | ||
| dependent_package=dependent_package, | ||
| dependency_name=dependency_name, | ||
| next_supported_version=next_supported_version, | ||
| version_used=version_used, | ||
| )) | ||
|
|
||
| def check_dependency_versions(dependent_package: str): | ||
| warn_deprecation_for_versions_less_than(dependent_package, "protobuf (google.protobuf)", "4.25.8") | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make this into a constant? Maybe DEFAULT_PACKAGE_DEPRECATION_TEMPLATE?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer not to because the message template is defined and directly used in one place, and it's closely coupled to the variables provided by the function. I think black-boxing it inside the function, and defining it where it's used, is clearer and more compact than defining a separate constant inside or outside the function.