google-analytics-admin 0.26.0__tar.gz → 0.27.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. {google_analytics_admin-0.26.0/google_analytics_admin.egg-info → google_analytics_admin-0.27.0}/PKG-INFO +1 -1
  2. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin/gapic_version.py +1 -1
  3. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/__init__.py +104 -0
  4. {google_analytics_admin-0.26.0/google/analytics/admin_v1beta → google_analytics_admin-0.27.0/google/analytics/admin_v1alpha}/gapic_version.py +1 -1
  5. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/client.py +32 -14
  6. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/__init__.py +104 -0
  7. {google_analytics_admin-0.26.0/google/analytics/admin_v1alpha → google_analytics_admin-0.27.0/google/analytics/admin_v1beta}/gapic_version.py +1 -1
  8. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/client.py +32 -14
  9. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0/google_analytics_admin.egg-info}/PKG-INFO +1 -1
  10. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/unit/gapic/admin_v1alpha/test_analytics_admin_service.py +226 -29
  11. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/unit/gapic/admin_v1beta/test_analytics_admin_service.py +226 -29
  12. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/LICENSE +0 -0
  13. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/MANIFEST.in +0 -0
  14. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/README.rst +0 -0
  15. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin/__init__.py +0 -0
  16. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin/py.typed +0 -0
  17. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/gapic_metadata.json +0 -0
  18. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/py.typed +0 -0
  19. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/__init__.py +0 -0
  20. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/__init__.py +0 -0
  21. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/async_client.py +0 -0
  22. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/pagers.py +0 -0
  23. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/transports/__init__.py +0 -0
  24. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/transports/base.py +0 -0
  25. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/transports/grpc.py +0 -0
  26. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/transports/grpc_asyncio.py +0 -0
  27. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/transports/rest.py +0 -0
  28. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/services/analytics_admin_service/transports/rest_base.py +0 -0
  29. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/__init__.py +0 -0
  30. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/access_report.py +0 -0
  31. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/analytics_admin.py +0 -0
  32. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/audience.py +0 -0
  33. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/channel_group.py +0 -0
  34. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/event_create_and_edit.py +0 -0
  35. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/expanded_data_set.py +0 -0
  36. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/resources.py +0 -0
  37. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1alpha/types/subproperty_event_filter.py +0 -0
  38. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/gapic_metadata.json +0 -0
  39. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/py.typed +0 -0
  40. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/__init__.py +0 -0
  41. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/__init__.py +0 -0
  42. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/async_client.py +0 -0
  43. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/pagers.py +0 -0
  44. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/transports/__init__.py +0 -0
  45. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/transports/base.py +0 -0
  46. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/transports/grpc.py +0 -0
  47. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/transports/grpc_asyncio.py +0 -0
  48. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/transports/rest.py +0 -0
  49. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/services/analytics_admin_service/transports/rest_base.py +0 -0
  50. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/types/__init__.py +0 -0
  51. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/types/access_report.py +0 -0
  52. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/types/analytics_admin.py +0 -0
  53. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google/analytics/admin_v1beta/types/resources.py +0 -0
  54. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google_analytics_admin.egg-info/SOURCES.txt +0 -0
  55. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google_analytics_admin.egg-info/dependency_links.txt +0 -0
  56. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google_analytics_admin.egg-info/not-zip-safe +0 -0
  57. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google_analytics_admin.egg-info/requires.txt +0 -0
  58. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/google_analytics_admin.egg-info/top_level.txt +0 -0
  59. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/setup.cfg +0 -0
  60. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/setup.py +0 -0
  61. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/__init__.py +0 -0
  62. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/unit/__init__.py +0 -0
  63. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/unit/gapic/__init__.py +0 -0
  64. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/unit/gapic/admin_v1alpha/__init__.py +0 -0
  65. {google_analytics_admin-0.26.0 → google_analytics_admin-0.27.0}/tests/unit/gapic/admin_v1beta/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-analytics-admin
3
- Version: 0.26.0
3
+ Version: 0.27.0
4
4
  Summary: Google Analytics Admin API client library
5
5
  Home-page: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-analytics-admin
6
6
  Author: Google LLC
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- __version__ = "0.26.0" # {x-release-please-version}
16
+ __version__ = "0.27.0" # {x-release-please-version}
@@ -13,10 +13,20 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
+ import sys
17
+
18
+ import google.api_core as api_core
19
+
16
20
  from google.analytics.admin_v1alpha import gapic_version as package_version
17
21
 
18
22
  __version__ = package_version.__version__
19
23
 
24
+ if sys.version_info >= (3, 8): # pragma: NO COVER
25
+ from importlib import metadata
26
+ else: # pragma: NO COVER
27
+ # TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
28
+ # this code path once we drop support for Python 3.7
29
+ import importlib_metadata as metadata
20
30
 
21
31
  from .services.analytics_admin_service import (
22
32
  AnalyticsAdminServiceAsyncClient,
@@ -327,6 +337,100 @@ from .types.subproperty_event_filter import (
327
337
  SubpropertyEventFilterExpressionList,
328
338
  )
329
339
 
340
+ if hasattr(api_core, "check_python_version") and hasattr(
341
+ api_core, "check_dependency_versions"
342
+ ): # pragma: NO COVER
343
+ api_core.check_python_version("google.analytics.admin_v1alpha") # type: ignore
344
+ api_core.check_dependency_versions("google.analytics.admin_v1alpha") # type: ignore
345
+ else: # pragma: NO COVER
346
+ # An older version of api_core is installed which does not define the
347
+ # functions above. We do equivalent checks manually.
348
+ try:
349
+ import sys
350
+ import warnings
351
+
352
+ _py_version_str = sys.version.split()[0]
353
+ _package_label = "google.analytics.admin_v1alpha"
354
+ if sys.version_info < (3, 9):
355
+ warnings.warn(
356
+ "You are using a non-supported Python version "
357
+ + f"({_py_version_str}). Google will not post any further "
358
+ + f"updates to {_package_label} supporting this Python version. "
359
+ + "Please upgrade to the latest Python version, or at "
360
+ + f"least to Python 3.9, and then update {_package_label}.",
361
+ FutureWarning,
362
+ )
363
+ if sys.version_info[:2] == (3, 9):
364
+ warnings.warn(
365
+ f"You are using a Python version ({_py_version_str}) "
366
+ + f"which Google will stop supporting in {_package_label} in "
367
+ + "January 2026. Please "
368
+ + "upgrade to the latest Python version, or at "
369
+ + "least to Python 3.10, before then, and "
370
+ + f"then update {_package_label}.",
371
+ FutureWarning,
372
+ )
373
+
374
+ def parse_version_to_tuple(version_string: str):
375
+ """Safely converts a semantic version string to a comparable tuple of integers.
376
+ Example: "4.25.8" -> (4, 25, 8)
377
+ Ignores non-numeric parts and handles common version formats.
378
+ Args:
379
+ version_string: Version string in the format "x.y.z" or "x.y.z<suffix>"
380
+ Returns:
381
+ Tuple of integers for the parsed version string.
382
+ """
383
+ parts = []
384
+ for part in version_string.split("."):
385
+ try:
386
+ parts.append(int(part))
387
+ except ValueError:
388
+ # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here.
389
+ # This is a simplification compared to 'packaging.parse_version', but sufficient
390
+ # for comparing strictly numeric semantic versions.
391
+ break
392
+ return tuple(parts)
393
+
394
+ def _get_version(dependency_name):
395
+ try:
396
+ version_string: str = metadata.version(dependency_name)
397
+ parsed_version = parse_version_to_tuple(version_string)
398
+ return (parsed_version, version_string)
399
+ except Exception:
400
+ # Catch exceptions from metadata.version() (e.g., PackageNotFoundError)
401
+ # or errors during parse_version_to_tuple
402
+ return (None, "--")
403
+
404
+ _dependency_package = "google.protobuf"
405
+ _next_supported_version = "4.25.8"
406
+ _next_supported_version_tuple = (4, 25, 8)
407
+ _recommendation = " (we recommend 6.x)"
408
+ (_version_used, _version_used_string) = _get_version(_dependency_package)
409
+ if _version_used and _version_used < _next_supported_version_tuple:
410
+ warnings.warn(
411
+ f"Package {_package_label} depends on "
412
+ + f"{_dependency_package}, currently installed at version "
413
+ + f"{_version_used_string}. Future updates to "
414
+ + f"{_package_label} will require {_dependency_package} at "
415
+ + f"version {_next_supported_version} or higher{_recommendation}."
416
+ + " Please ensure "
417
+ + "that either (a) your Python environment doesn't pin the "
418
+ + f"version of {_dependency_package}, so that updates to "
419
+ + f"{_package_label} can require the higher version, or "
420
+ + "(b) you manually update your Python environment to use at "
421
+ + f"least version {_next_supported_version} of "
422
+ + f"{_dependency_package}.",
423
+ FutureWarning,
424
+ )
425
+ except Exception:
426
+ warnings.warn(
427
+ "Could not determine the version of Python "
428
+ + "currently being used. To continue receiving "
429
+ + "updates for {_package_label}, ensure you are "
430
+ + "using a supported version of Python; see "
431
+ + "https://devguide.python.org/versions/"
432
+ )
433
+
330
434
  __all__ = (
331
435
  "AnalyticsAdminServiceAsyncClient",
332
436
  "AccessBetweenFilter",
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- __version__ = "0.26.0" # {x-release-please-version}
16
+ __version__ = "0.27.0" # {x-release-please-version}
@@ -168,6 +168,34 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
168
168
  _DEFAULT_ENDPOINT_TEMPLATE = "analyticsadmin.{UNIVERSE_DOMAIN}"
169
169
  _DEFAULT_UNIVERSE = "googleapis.com"
170
170
 
171
+ @staticmethod
172
+ def _use_client_cert_effective():
173
+ """Returns whether client certificate should be used for mTLS if the
174
+ google-auth version supports should_use_client_cert automatic mTLS enablement.
175
+
176
+ Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var.
177
+
178
+ Returns:
179
+ bool: whether client certificate should be used for mTLS
180
+ Raises:
181
+ ValueError: (If using a version of google-auth without should_use_client_cert and
182
+ GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.)
183
+ """
184
+ # check if google-auth version supports should_use_client_cert for automatic mTLS enablement
185
+ if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER
186
+ return mtls.should_use_client_cert()
187
+ else: # pragma: NO COVER
188
+ # if unsupported, fallback to reading from env var
189
+ use_client_cert_str = os.getenv(
190
+ "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
191
+ ).lower()
192
+ if use_client_cert_str not in ("true", "false"):
193
+ raise ValueError(
194
+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
195
+ " either `true` or `false`"
196
+ )
197
+ return use_client_cert_str == "true"
198
+
171
199
  @classmethod
172
200
  def from_service_account_info(cls, info: dict, *args, **kwargs):
173
201
  """Creates an instance of this client using the provided credentials
@@ -1029,12 +1057,8 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
1029
1057
  )
1030
1058
  if client_options is None:
1031
1059
  client_options = client_options_lib.ClientOptions()
1032
- use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
1060
+ use_client_cert = AnalyticsAdminServiceClient._use_client_cert_effective()
1033
1061
  use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
1034
- if use_client_cert not in ("true", "false"):
1035
- raise ValueError(
1036
- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
1037
- )
1038
1062
  if use_mtls_endpoint not in ("auto", "never", "always"):
1039
1063
  raise MutualTLSChannelError(
1040
1064
  "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
@@ -1042,7 +1066,7 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
1042
1066
 
1043
1067
  # Figure out the client cert source to use.
1044
1068
  client_cert_source = None
1045
- if use_client_cert == "true":
1069
+ if use_client_cert:
1046
1070
  if client_options.client_cert_source:
1047
1071
  client_cert_source = client_options.client_cert_source
1048
1072
  elif mtls.has_default_client_cert_source():
@@ -1074,20 +1098,14 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
1074
1098
  google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT
1075
1099
  is not any of ["auto", "never", "always"].
1076
1100
  """
1077
- use_client_cert = os.getenv(
1078
- "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
1079
- ).lower()
1101
+ use_client_cert = AnalyticsAdminServiceClient._use_client_cert_effective()
1080
1102
  use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower()
1081
1103
  universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN")
1082
- if use_client_cert not in ("true", "false"):
1083
- raise ValueError(
1084
- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
1085
- )
1086
1104
  if use_mtls_endpoint not in ("auto", "never", "always"):
1087
1105
  raise MutualTLSChannelError(
1088
1106
  "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
1089
1107
  )
1090
- return use_client_cert == "true", use_mtls_endpoint, universe_domain_env
1108
+ return use_client_cert, use_mtls_endpoint, universe_domain_env
1091
1109
 
1092
1110
  @staticmethod
1093
1111
  def _get_client_cert_source(provided_cert_source, use_cert_flag):
@@ -13,10 +13,20 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
+ import sys
17
+
18
+ import google.api_core as api_core
19
+
16
20
  from google.analytics.admin_v1beta import gapic_version as package_version
17
21
 
18
22
  __version__ = package_version.__version__
19
23
 
24
+ if sys.version_info >= (3, 8): # pragma: NO COVER
25
+ from importlib import metadata
26
+ else: # pragma: NO COVER
27
+ # TODO(https://github.com/googleapis/python-api-core/issues/835): Remove
28
+ # this code path once we drop support for Python 3.7
29
+ import importlib_metadata as metadata
20
30
 
21
31
  from .services.analytics_admin_service import (
22
32
  AnalyticsAdminServiceAsyncClient,
@@ -139,6 +149,100 @@ from .types.resources import (
139
149
  ServiceLevel,
140
150
  )
141
151
 
152
+ if hasattr(api_core, "check_python_version") and hasattr(
153
+ api_core, "check_dependency_versions"
154
+ ): # pragma: NO COVER
155
+ api_core.check_python_version("google.analytics.admin_v1beta") # type: ignore
156
+ api_core.check_dependency_versions("google.analytics.admin_v1beta") # type: ignore
157
+ else: # pragma: NO COVER
158
+ # An older version of api_core is installed which does not define the
159
+ # functions above. We do equivalent checks manually.
160
+ try:
161
+ import sys
162
+ import warnings
163
+
164
+ _py_version_str = sys.version.split()[0]
165
+ _package_label = "google.analytics.admin_v1beta"
166
+ if sys.version_info < (3, 9):
167
+ warnings.warn(
168
+ "You are using a non-supported Python version "
169
+ + f"({_py_version_str}). Google will not post any further "
170
+ + f"updates to {_package_label} supporting this Python version. "
171
+ + "Please upgrade to the latest Python version, or at "
172
+ + f"least to Python 3.9, and then update {_package_label}.",
173
+ FutureWarning,
174
+ )
175
+ if sys.version_info[:2] == (3, 9):
176
+ warnings.warn(
177
+ f"You are using a Python version ({_py_version_str}) "
178
+ + f"which Google will stop supporting in {_package_label} in "
179
+ + "January 2026. Please "
180
+ + "upgrade to the latest Python version, or at "
181
+ + "least to Python 3.10, before then, and "
182
+ + f"then update {_package_label}.",
183
+ FutureWarning,
184
+ )
185
+
186
+ def parse_version_to_tuple(version_string: str):
187
+ """Safely converts a semantic version string to a comparable tuple of integers.
188
+ Example: "4.25.8" -> (4, 25, 8)
189
+ Ignores non-numeric parts and handles common version formats.
190
+ Args:
191
+ version_string: Version string in the format "x.y.z" or "x.y.z<suffix>"
192
+ Returns:
193
+ Tuple of integers for the parsed version string.
194
+ """
195
+ parts = []
196
+ for part in version_string.split("."):
197
+ try:
198
+ parts.append(int(part))
199
+ except ValueError:
200
+ # If it's a non-numeric part (e.g., '1.0.0b1' -> 'b1'), stop here.
201
+ # This is a simplification compared to 'packaging.parse_version', but sufficient
202
+ # for comparing strictly numeric semantic versions.
203
+ break
204
+ return tuple(parts)
205
+
206
+ def _get_version(dependency_name):
207
+ try:
208
+ version_string: str = metadata.version(dependency_name)
209
+ parsed_version = parse_version_to_tuple(version_string)
210
+ return (parsed_version, version_string)
211
+ except Exception:
212
+ # Catch exceptions from metadata.version() (e.g., PackageNotFoundError)
213
+ # or errors during parse_version_to_tuple
214
+ return (None, "--")
215
+
216
+ _dependency_package = "google.protobuf"
217
+ _next_supported_version = "4.25.8"
218
+ _next_supported_version_tuple = (4, 25, 8)
219
+ _recommendation = " (we recommend 6.x)"
220
+ (_version_used, _version_used_string) = _get_version(_dependency_package)
221
+ if _version_used and _version_used < _next_supported_version_tuple:
222
+ warnings.warn(
223
+ f"Package {_package_label} depends on "
224
+ + f"{_dependency_package}, currently installed at version "
225
+ + f"{_version_used_string}. Future updates to "
226
+ + f"{_package_label} will require {_dependency_package} at "
227
+ + f"version {_next_supported_version} or higher{_recommendation}."
228
+ + " Please ensure "
229
+ + "that either (a) your Python environment doesn't pin the "
230
+ + f"version of {_dependency_package}, so that updates to "
231
+ + f"{_package_label} can require the higher version, or "
232
+ + "(b) you manually update your Python environment to use at "
233
+ + f"least version {_next_supported_version} of "
234
+ + f"{_dependency_package}.",
235
+ FutureWarning,
236
+ )
237
+ except Exception:
238
+ warnings.warn(
239
+ "Could not determine the version of Python "
240
+ + "currently being used. To continue receiving "
241
+ + "updates for {_package_label}, ensure you are "
242
+ + "using a supported version of Python; see "
243
+ + "https://devguide.python.org/versions/"
244
+ )
245
+
142
246
  __all__ = (
143
247
  "AnalyticsAdminServiceAsyncClient",
144
248
  "AccessBetweenFilter",
@@ -13,4 +13,4 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- __version__ = "0.26.0" # {x-release-please-version}
16
+ __version__ = "0.27.0" # {x-release-please-version}
@@ -157,6 +157,34 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
157
157
  _DEFAULT_ENDPOINT_TEMPLATE = "analyticsadmin.{UNIVERSE_DOMAIN}"
158
158
  _DEFAULT_UNIVERSE = "googleapis.com"
159
159
 
160
+ @staticmethod
161
+ def _use_client_cert_effective():
162
+ """Returns whether client certificate should be used for mTLS if the
163
+ google-auth version supports should_use_client_cert automatic mTLS enablement.
164
+
165
+ Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var.
166
+
167
+ Returns:
168
+ bool: whether client certificate should be used for mTLS
169
+ Raises:
170
+ ValueError: (If using a version of google-auth without should_use_client_cert and
171
+ GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.)
172
+ """
173
+ # check if google-auth version supports should_use_client_cert for automatic mTLS enablement
174
+ if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER
175
+ return mtls.should_use_client_cert()
176
+ else: # pragma: NO COVER
177
+ # if unsupported, fallback to reading from env var
178
+ use_client_cert_str = os.getenv(
179
+ "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
180
+ ).lower()
181
+ if use_client_cert_str not in ("true", "false"):
182
+ raise ValueError(
183
+ "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
184
+ " either `true` or `false`"
185
+ )
186
+ return use_client_cert_str == "true"
187
+
160
188
  @classmethod
161
189
  def from_service_account_info(cls, info: dict, *args, **kwargs):
162
190
  """Creates an instance of this client using the provided credentials
@@ -570,12 +598,8 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
570
598
  )
571
599
  if client_options is None:
572
600
  client_options = client_options_lib.ClientOptions()
573
- use_client_cert = os.getenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
601
+ use_client_cert = AnalyticsAdminServiceClient._use_client_cert_effective()
574
602
  use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
575
- if use_client_cert not in ("true", "false"):
576
- raise ValueError(
577
- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
578
- )
579
603
  if use_mtls_endpoint not in ("auto", "never", "always"):
580
604
  raise MutualTLSChannelError(
581
605
  "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
@@ -583,7 +607,7 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
583
607
 
584
608
  # Figure out the client cert source to use.
585
609
  client_cert_source = None
586
- if use_client_cert == "true":
610
+ if use_client_cert:
587
611
  if client_options.client_cert_source:
588
612
  client_cert_source = client_options.client_cert_source
589
613
  elif mtls.has_default_client_cert_source():
@@ -615,20 +639,14 @@ class AnalyticsAdminServiceClient(metaclass=AnalyticsAdminServiceClientMeta):
615
639
  google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT
616
640
  is not any of ["auto", "never", "always"].
617
641
  """
618
- use_client_cert = os.getenv(
619
- "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
620
- ).lower()
642
+ use_client_cert = AnalyticsAdminServiceClient._use_client_cert_effective()
621
643
  use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower()
622
644
  universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN")
623
- if use_client_cert not in ("true", "false"):
624
- raise ValueError(
625
- "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
626
- )
627
645
  if use_mtls_endpoint not in ("auto", "never", "always"):
628
646
  raise MutualTLSChannelError(
629
647
  "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
630
648
  )
631
- return use_client_cert == "true", use_mtls_endpoint, universe_domain_env
649
+ return use_client_cert, use_mtls_endpoint, universe_domain_env
632
650
 
633
651
  @staticmethod
634
652
  def _get_client_cert_source(provided_cert_source, use_cert_flag):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-analytics-admin
3
- Version: 0.26.0
3
+ Version: 0.27.0
4
4
  Summary: Google Analytics Admin API client library
5
5
  Home-page: https://github.com/googleapis/google-cloud-python/tree/main/packages/google-analytics-admin
6
6
  Author: Google LLC
@@ -181,12 +181,19 @@ def test__read_environment_variables():
181
181
  with mock.patch.dict(
182
182
  os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
183
183
  ):
184
- with pytest.raises(ValueError) as excinfo:
185
- AnalyticsAdminServiceClient._read_environment_variables()
186
- assert (
187
- str(excinfo.value)
188
- == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
189
- )
184
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
185
+ with pytest.raises(ValueError) as excinfo:
186
+ AnalyticsAdminServiceClient._read_environment_variables()
187
+ assert (
188
+ str(excinfo.value)
189
+ == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
190
+ )
191
+ else:
192
+ assert AnalyticsAdminServiceClient._read_environment_variables() == (
193
+ False,
194
+ "auto",
195
+ None,
196
+ )
190
197
 
191
198
  with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
192
199
  assert AnalyticsAdminServiceClient._read_environment_variables() == (
@@ -225,6 +232,105 @@ def test__read_environment_variables():
225
232
  )
226
233
 
227
234
 
235
+ def test_use_client_cert_effective():
236
+ # Test case 1: Test when `should_use_client_cert` returns True.
237
+ # We mock the `should_use_client_cert` function to simulate a scenario where
238
+ # the google-auth library supports automatic mTLS and determines that a
239
+ # client certificate should be used.
240
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
241
+ with mock.patch(
242
+ "google.auth.transport.mtls.should_use_client_cert", return_value=True
243
+ ):
244
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
245
+
246
+ # Test case 2: Test when `should_use_client_cert` returns False.
247
+ # We mock the `should_use_client_cert` function to simulate a scenario where
248
+ # the google-auth library supports automatic mTLS and determines that a
249
+ # client certificate should NOT be used.
250
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
251
+ with mock.patch(
252
+ "google.auth.transport.mtls.should_use_client_cert", return_value=False
253
+ ):
254
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
255
+
256
+ # Test case 3: Test when `should_use_client_cert` is unavailable and the
257
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true".
258
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
259
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
260
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
261
+
262
+ # Test case 4: Test when `should_use_client_cert` is unavailable and the
263
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false".
264
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
265
+ with mock.patch.dict(
266
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}
267
+ ):
268
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
269
+
270
+ # Test case 5: Test when `should_use_client_cert` is unavailable and the
271
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True".
272
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
273
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}):
274
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
275
+
276
+ # Test case 6: Test when `should_use_client_cert` is unavailable and the
277
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False".
278
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
279
+ with mock.patch.dict(
280
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}
281
+ ):
282
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
283
+
284
+ # Test case 7: Test when `should_use_client_cert` is unavailable and the
285
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE".
286
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
287
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}):
288
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
289
+
290
+ # Test case 8: Test when `should_use_client_cert` is unavailable and the
291
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE".
292
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
293
+ with mock.patch.dict(
294
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}
295
+ ):
296
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
297
+
298
+ # Test case 9: Test when `should_use_client_cert` is unavailable and the
299
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set.
300
+ # In this case, the method should return False, which is the default value.
301
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
302
+ with mock.patch.dict(os.environ, clear=True):
303
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
304
+
305
+ # Test case 10: Test when `should_use_client_cert` is unavailable and the
306
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value.
307
+ # The method should raise a ValueError as the environment variable must be either
308
+ # "true" or "false".
309
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
310
+ with mock.patch.dict(
311
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}
312
+ ):
313
+ with pytest.raises(ValueError):
314
+ AnalyticsAdminServiceClient._use_client_cert_effective()
315
+
316
+ # Test case 11: Test when `should_use_client_cert` is available and the
317
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value.
318
+ # The method should return False as the environment variable is set to an invalid value.
319
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
320
+ with mock.patch.dict(
321
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}
322
+ ):
323
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
324
+
325
+ # Test case 12: Test when `should_use_client_cert` is available and the
326
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also,
327
+ # the GOOGLE_API_CONFIG environment variable is unset.
328
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
329
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}):
330
+ with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}):
331
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
332
+
333
+
228
334
  def test__get_client_cert_source():
229
335
  mock_provided_cert_source = mock.Mock()
230
336
  mock_default_cert_source = mock.Mock()
@@ -614,17 +720,6 @@ def test_analytics_admin_service_client_client_options(
614
720
  == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
615
721
  )
616
722
 
617
- # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value.
618
- with mock.patch.dict(
619
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
620
- ):
621
- with pytest.raises(ValueError) as excinfo:
622
- client = client_class(transport=transport_name)
623
- assert (
624
- str(excinfo.value)
625
- == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
626
- )
627
-
628
723
  # Check the case quota_project_id is provided
629
724
  options = client_options.ClientOptions(quota_project_id="octopus")
630
725
  with mock.patch.object(transport_class, "__init__") as patched:
@@ -860,6 +955,119 @@ def test_analytics_admin_service_client_get_mtls_endpoint_and_cert_source(client
860
955
  assert api_endpoint == mock_api_endpoint
861
956
  assert cert_source is None
862
957
 
958
+ # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "Unsupported".
959
+ with mock.patch.dict(
960
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
961
+ ):
962
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
963
+ mock_client_cert_source = mock.Mock()
964
+ mock_api_endpoint = "foo"
965
+ options = client_options.ClientOptions(
966
+ client_cert_source=mock_client_cert_source,
967
+ api_endpoint=mock_api_endpoint,
968
+ )
969
+ api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
970
+ options
971
+ )
972
+ assert api_endpoint == mock_api_endpoint
973
+ assert cert_source is None
974
+
975
+ # Test cases for mTLS enablement when GOOGLE_API_USE_CLIENT_CERTIFICATE is unset.
976
+ test_cases = [
977
+ (
978
+ # With workloads present in config, mTLS is enabled.
979
+ {
980
+ "version": 1,
981
+ "cert_configs": {
982
+ "workload": {
983
+ "cert_path": "path/to/cert/file",
984
+ "key_path": "path/to/key/file",
985
+ }
986
+ },
987
+ },
988
+ mock_client_cert_source,
989
+ ),
990
+ (
991
+ # With workloads not present in config, mTLS is disabled.
992
+ {
993
+ "version": 1,
994
+ "cert_configs": {},
995
+ },
996
+ None,
997
+ ),
998
+ ]
999
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
1000
+ for config_data, expected_cert_source in test_cases:
1001
+ env = os.environ.copy()
1002
+ env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None)
1003
+ with mock.patch.dict(os.environ, env, clear=True):
1004
+ config_filename = "mock_certificate_config.json"
1005
+ config_file_content = json.dumps(config_data)
1006
+ m = mock.mock_open(read_data=config_file_content)
1007
+ with mock.patch("builtins.open", m):
1008
+ with mock.patch.dict(
1009
+ os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": config_filename}
1010
+ ):
1011
+ mock_api_endpoint = "foo"
1012
+ options = client_options.ClientOptions(
1013
+ client_cert_source=mock_client_cert_source,
1014
+ api_endpoint=mock_api_endpoint,
1015
+ )
1016
+ (
1017
+ api_endpoint,
1018
+ cert_source,
1019
+ ) = client_class.get_mtls_endpoint_and_cert_source(options)
1020
+ assert api_endpoint == mock_api_endpoint
1021
+ assert cert_source is expected_cert_source
1022
+
1023
+ # Test cases for mTLS enablement when GOOGLE_API_USE_CLIENT_CERTIFICATE is unset(empty).
1024
+ test_cases = [
1025
+ (
1026
+ # With workloads present in config, mTLS is enabled.
1027
+ {
1028
+ "version": 1,
1029
+ "cert_configs": {
1030
+ "workload": {
1031
+ "cert_path": "path/to/cert/file",
1032
+ "key_path": "path/to/key/file",
1033
+ }
1034
+ },
1035
+ },
1036
+ mock_client_cert_source,
1037
+ ),
1038
+ (
1039
+ # With workloads not present in config, mTLS is disabled.
1040
+ {
1041
+ "version": 1,
1042
+ "cert_configs": {},
1043
+ },
1044
+ None,
1045
+ ),
1046
+ ]
1047
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
1048
+ for config_data, expected_cert_source in test_cases:
1049
+ env = os.environ.copy()
1050
+ env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
1051
+ with mock.patch.dict(os.environ, env, clear=True):
1052
+ config_filename = "mock_certificate_config.json"
1053
+ config_file_content = json.dumps(config_data)
1054
+ m = mock.mock_open(read_data=config_file_content)
1055
+ with mock.patch("builtins.open", m):
1056
+ with mock.patch.dict(
1057
+ os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": config_filename}
1058
+ ):
1059
+ mock_api_endpoint = "foo"
1060
+ options = client_options.ClientOptions(
1061
+ client_cert_source=mock_client_cert_source,
1062
+ api_endpoint=mock_api_endpoint,
1063
+ )
1064
+ (
1065
+ api_endpoint,
1066
+ cert_source,
1067
+ ) = client_class.get_mtls_endpoint_and_cert_source(options)
1068
+ assert api_endpoint == mock_api_endpoint
1069
+ assert cert_source is expected_cert_source
1070
+
863
1071
  # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never".
864
1072
  with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
865
1073
  api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
@@ -910,18 +1118,6 @@ def test_analytics_admin_service_client_get_mtls_endpoint_and_cert_source(client
910
1118
  == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
911
1119
  )
912
1120
 
913
- # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value.
914
- with mock.patch.dict(
915
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
916
- ):
917
- with pytest.raises(ValueError) as excinfo:
918
- client_class.get_mtls_endpoint_and_cert_source()
919
-
920
- assert (
921
- str(excinfo.value)
922
- == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
923
- )
924
-
925
1121
 
926
1122
  @pytest.mark.parametrize(
927
1123
  "client_class", [AnalyticsAdminServiceClient, AnalyticsAdminServiceAsyncClient]
@@ -126856,6 +127052,7 @@ def test_analytics_admin_service_grpc_asyncio_transport_channel():
126856
127052
 
126857
127053
  # Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
126858
127054
  # removed from grpc/grpc_asyncio transport constructor.
127055
+ @pytest.mark.filterwarnings("ignore::FutureWarning")
126859
127056
  @pytest.mark.parametrize(
126860
127057
  "transport_class",
126861
127058
  [
@@ -169,12 +169,19 @@ def test__read_environment_variables():
169
169
  with mock.patch.dict(
170
170
  os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
171
171
  ):
172
- with pytest.raises(ValueError) as excinfo:
173
- AnalyticsAdminServiceClient._read_environment_variables()
174
- assert (
175
- str(excinfo.value)
176
- == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
177
- )
172
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
173
+ with pytest.raises(ValueError) as excinfo:
174
+ AnalyticsAdminServiceClient._read_environment_variables()
175
+ assert (
176
+ str(excinfo.value)
177
+ == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
178
+ )
179
+ else:
180
+ assert AnalyticsAdminServiceClient._read_environment_variables() == (
181
+ False,
182
+ "auto",
183
+ None,
184
+ )
178
185
 
179
186
  with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
180
187
  assert AnalyticsAdminServiceClient._read_environment_variables() == (
@@ -213,6 +220,105 @@ def test__read_environment_variables():
213
220
  )
214
221
 
215
222
 
223
+ def test_use_client_cert_effective():
224
+ # Test case 1: Test when `should_use_client_cert` returns True.
225
+ # We mock the `should_use_client_cert` function to simulate a scenario where
226
+ # the google-auth library supports automatic mTLS and determines that a
227
+ # client certificate should be used.
228
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
229
+ with mock.patch(
230
+ "google.auth.transport.mtls.should_use_client_cert", return_value=True
231
+ ):
232
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
233
+
234
+ # Test case 2: Test when `should_use_client_cert` returns False.
235
+ # We mock the `should_use_client_cert` function to simulate a scenario where
236
+ # the google-auth library supports automatic mTLS and determines that a
237
+ # client certificate should NOT be used.
238
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
239
+ with mock.patch(
240
+ "google.auth.transport.mtls.should_use_client_cert", return_value=False
241
+ ):
242
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
243
+
244
+ # Test case 3: Test when `should_use_client_cert` is unavailable and the
245
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "true".
246
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
247
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "true"}):
248
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
249
+
250
+ # Test case 4: Test when `should_use_client_cert` is unavailable and the
251
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "false".
252
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
253
+ with mock.patch.dict(
254
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "false"}
255
+ ):
256
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
257
+
258
+ # Test case 5: Test when `should_use_client_cert` is unavailable and the
259
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "True".
260
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
261
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "True"}):
262
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
263
+
264
+ # Test case 6: Test when `should_use_client_cert` is unavailable and the
265
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "False".
266
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
267
+ with mock.patch.dict(
268
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "False"}
269
+ ):
270
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
271
+
272
+ # Test case 7: Test when `should_use_client_cert` is unavailable and the
273
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "TRUE".
274
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
275
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "TRUE"}):
276
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is True
277
+
278
+ # Test case 8: Test when `should_use_client_cert` is unavailable and the
279
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to "FALSE".
280
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
281
+ with mock.patch.dict(
282
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "FALSE"}
283
+ ):
284
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
285
+
286
+ # Test case 9: Test when `should_use_client_cert` is unavailable and the
287
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not set.
288
+ # In this case, the method should return False, which is the default value.
289
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
290
+ with mock.patch.dict(os.environ, clear=True):
291
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
292
+
293
+ # Test case 10: Test when `should_use_client_cert` is unavailable and the
294
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value.
295
+ # The method should raise a ValueError as the environment variable must be either
296
+ # "true" or "false".
297
+ if not hasattr(google.auth.transport.mtls, "should_use_client_cert"):
298
+ with mock.patch.dict(
299
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}
300
+ ):
301
+ with pytest.raises(ValueError):
302
+ AnalyticsAdminServiceClient._use_client_cert_effective()
303
+
304
+ # Test case 11: Test when `should_use_client_cert` is available and the
305
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is set to an invalid value.
306
+ # The method should return False as the environment variable is set to an invalid value.
307
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
308
+ with mock.patch.dict(
309
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "unsupported"}
310
+ ):
311
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
312
+
313
+ # Test case 12: Test when `should_use_client_cert` is available and the
314
+ # `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is unset. Also,
315
+ # the GOOGLE_API_CONFIG environment variable is unset.
316
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
317
+ with mock.patch.dict(os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": ""}):
318
+ with mock.patch.dict(os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": ""}):
319
+ assert AnalyticsAdminServiceClient._use_client_cert_effective() is False
320
+
321
+
216
322
  def test__get_client_cert_source():
217
323
  mock_provided_cert_source = mock.Mock()
218
324
  mock_default_cert_source = mock.Mock()
@@ -602,17 +708,6 @@ def test_analytics_admin_service_client_client_options(
602
708
  == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
603
709
  )
604
710
 
605
- # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value.
606
- with mock.patch.dict(
607
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
608
- ):
609
- with pytest.raises(ValueError) as excinfo:
610
- client = client_class(transport=transport_name)
611
- assert (
612
- str(excinfo.value)
613
- == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
614
- )
615
-
616
711
  # Check the case quota_project_id is provided
617
712
  options = client_options.ClientOptions(quota_project_id="octopus")
618
713
  with mock.patch.object(transport_class, "__init__") as patched:
@@ -848,6 +943,119 @@ def test_analytics_admin_service_client_get_mtls_endpoint_and_cert_source(client
848
943
  assert api_endpoint == mock_api_endpoint
849
944
  assert cert_source is None
850
945
 
946
+ # Test the case GOOGLE_API_USE_CLIENT_CERTIFICATE is "Unsupported".
947
+ with mock.patch.dict(
948
+ os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
949
+ ):
950
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
951
+ mock_client_cert_source = mock.Mock()
952
+ mock_api_endpoint = "foo"
953
+ options = client_options.ClientOptions(
954
+ client_cert_source=mock_client_cert_source,
955
+ api_endpoint=mock_api_endpoint,
956
+ )
957
+ api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source(
958
+ options
959
+ )
960
+ assert api_endpoint == mock_api_endpoint
961
+ assert cert_source is None
962
+
963
+ # Test cases for mTLS enablement when GOOGLE_API_USE_CLIENT_CERTIFICATE is unset.
964
+ test_cases = [
965
+ (
966
+ # With workloads present in config, mTLS is enabled.
967
+ {
968
+ "version": 1,
969
+ "cert_configs": {
970
+ "workload": {
971
+ "cert_path": "path/to/cert/file",
972
+ "key_path": "path/to/key/file",
973
+ }
974
+ },
975
+ },
976
+ mock_client_cert_source,
977
+ ),
978
+ (
979
+ # With workloads not present in config, mTLS is disabled.
980
+ {
981
+ "version": 1,
982
+ "cert_configs": {},
983
+ },
984
+ None,
985
+ ),
986
+ ]
987
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
988
+ for config_data, expected_cert_source in test_cases:
989
+ env = os.environ.copy()
990
+ env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", None)
991
+ with mock.patch.dict(os.environ, env, clear=True):
992
+ config_filename = "mock_certificate_config.json"
993
+ config_file_content = json.dumps(config_data)
994
+ m = mock.mock_open(read_data=config_file_content)
995
+ with mock.patch("builtins.open", m):
996
+ with mock.patch.dict(
997
+ os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": config_filename}
998
+ ):
999
+ mock_api_endpoint = "foo"
1000
+ options = client_options.ClientOptions(
1001
+ client_cert_source=mock_client_cert_source,
1002
+ api_endpoint=mock_api_endpoint,
1003
+ )
1004
+ (
1005
+ api_endpoint,
1006
+ cert_source,
1007
+ ) = client_class.get_mtls_endpoint_and_cert_source(options)
1008
+ assert api_endpoint == mock_api_endpoint
1009
+ assert cert_source is expected_cert_source
1010
+
1011
+ # Test cases for mTLS enablement when GOOGLE_API_USE_CLIENT_CERTIFICATE is unset(empty).
1012
+ test_cases = [
1013
+ (
1014
+ # With workloads present in config, mTLS is enabled.
1015
+ {
1016
+ "version": 1,
1017
+ "cert_configs": {
1018
+ "workload": {
1019
+ "cert_path": "path/to/cert/file",
1020
+ "key_path": "path/to/key/file",
1021
+ }
1022
+ },
1023
+ },
1024
+ mock_client_cert_source,
1025
+ ),
1026
+ (
1027
+ # With workloads not present in config, mTLS is disabled.
1028
+ {
1029
+ "version": 1,
1030
+ "cert_configs": {},
1031
+ },
1032
+ None,
1033
+ ),
1034
+ ]
1035
+ if hasattr(google.auth.transport.mtls, "should_use_client_cert"):
1036
+ for config_data, expected_cert_source in test_cases:
1037
+ env = os.environ.copy()
1038
+ env.pop("GOOGLE_API_USE_CLIENT_CERTIFICATE", "")
1039
+ with mock.patch.dict(os.environ, env, clear=True):
1040
+ config_filename = "mock_certificate_config.json"
1041
+ config_file_content = json.dumps(config_data)
1042
+ m = mock.mock_open(read_data=config_file_content)
1043
+ with mock.patch("builtins.open", m):
1044
+ with mock.patch.dict(
1045
+ os.environ, {"GOOGLE_API_CERTIFICATE_CONFIG": config_filename}
1046
+ ):
1047
+ mock_api_endpoint = "foo"
1048
+ options = client_options.ClientOptions(
1049
+ client_cert_source=mock_client_cert_source,
1050
+ api_endpoint=mock_api_endpoint,
1051
+ )
1052
+ (
1053
+ api_endpoint,
1054
+ cert_source,
1055
+ ) = client_class.get_mtls_endpoint_and_cert_source(options)
1056
+ assert api_endpoint == mock_api_endpoint
1057
+ assert cert_source is expected_cert_source
1058
+
851
1059
  # Test the case GOOGLE_API_USE_MTLS_ENDPOINT is "never".
852
1060
  with mock.patch.dict(os.environ, {"GOOGLE_API_USE_MTLS_ENDPOINT": "never"}):
853
1061
  api_endpoint, cert_source = client_class.get_mtls_endpoint_and_cert_source()
@@ -898,18 +1106,6 @@ def test_analytics_admin_service_client_get_mtls_endpoint_and_cert_source(client
898
1106
  == "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
899
1107
  )
900
1108
 
901
- # Check the case GOOGLE_API_USE_CLIENT_CERTIFICATE has unsupported value.
902
- with mock.patch.dict(
903
- os.environ, {"GOOGLE_API_USE_CLIENT_CERTIFICATE": "Unsupported"}
904
- ):
905
- with pytest.raises(ValueError) as excinfo:
906
- client_class.get_mtls_endpoint_and_cert_source()
907
-
908
- assert (
909
- str(excinfo.value)
910
- == "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be either `true` or `false`"
911
- )
912
-
913
1109
 
914
1110
  @pytest.mark.parametrize(
915
1111
  "client_class", [AnalyticsAdminServiceClient, AnalyticsAdminServiceAsyncClient]
@@ -44994,6 +45190,7 @@ def test_analytics_admin_service_grpc_asyncio_transport_channel():
44994
45190
 
44995
45191
  # Remove this test when deprecated arguments (api_mtls_endpoint, client_cert_source) are
44996
45192
  # removed from grpc/grpc_asyncio transport constructor.
45193
+ @pytest.mark.filterwarnings("ignore::FutureWarning")
44997
45194
  @pytest.mark.parametrize(
44998
45195
  "transport_class",
44999
45196
  [