Skip to content

Commit dbd4f5f

Browse files
committed
feat(templates): remove pragmas from _compat.py and add test_compat.py unit test template for 100% coverage
1 parent 4709121 commit dbd4f5f

18 files changed

Lines changed: 1130 additions & 108 deletions

File tree

packages/gapic-generator/gapic/templates/%namespace/%name_%version/%sub/_compat.py.j2

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ try:
1919
get_api_endpoint,
2020
get_universe_domain,
2121
)
22-
except ImportError: # pragma: NO COVER
22+
except ImportError:
2323
# TODO(https://github.com/googleapis/google-cloud-python/issues/17813): Universe domain support was introduced in google-api-core 2.18.0.
2424
# Remove these fallback definitions when google-api-core >= 2.18.0 becomes the minimum required version in generated client setup dependencies.
2525
def get_default_mtls_endpoint(api_endpoint: Optional[str]) -> Optional[str]:
@@ -91,7 +91,7 @@ try:
9191
get_client_cert_source,
9292
read_environment_variables,
9393
)
94-
except ImportError: # pragma: NO COVER
94+
except ImportError:
9595
from google.auth.transport import mtls # type: ignore
9696

9797
# TODO(https://github.com/googleapis/google-cloud-python/issues/17813): Remove these fallbacks when google-api-core >= 2.18.0 is the minimum required version.
@@ -144,7 +144,7 @@ except ImportError: # pragma: NO COVER
144144

145145
try:
146146
from google.api_core.gapic_v1.request import setup_request_id # type: ignore
147-
except ImportError: # pragma: NO COVER
147+
except ImportError:
148148
# TODO(https://github.com/googleapis/google-cloud-python/issues/17813): Request ID setup helper was introduced in google-api-core 2.26.0.
149149
# Remove this fallback definition when google-api-core >= 2.26.0 becomes the minimum required version in generated client setup dependencies.
150150
def setup_request_id(request, field_name: str, is_proto3_optional: bool):
@@ -194,17 +194,17 @@ try:
194194
flatten_query_params,
195195
transcode_request,
196196
)
197-
except ImportError: # pragma: NO COVER
197+
except ImportError:
198198
# TODO: Remove these fallbacks when google-api-core >= 2.18.0 is the minimum required version.
199199
from google.protobuf import json_format # type: ignore
200200
from google.api_core import path_template # type: ignore
201201

202-
def flatten_query_params(obj, strict=False): # pragma: NO COVER
202+
def flatten_query_params(obj, strict=False):
203203
if obj is not None and not isinstance(obj, dict):
204204
raise TypeError("flatten_query_params must be called with dict object")
205205
return _flatten(obj, key_path=[], strict=strict)
206206

207-
def _flatten(obj, key_path, strict=False): # pragma: NO COVER
207+
def _flatten(obj, key_path, strict=False):
208208
if obj is None:
209209
return []
210210
if isinstance(obj, dict):
@@ -213,40 +213,40 @@ except ImportError: # pragma: NO COVER
213213
return _flatten_list(obj, key_path=key_path, strict=strict)
214214
return _flatten_value(obj, key_path=key_path, strict=strict)
215215

216-
def _is_primitive_value(obj): # pragma: NO COVER
216+
def _is_primitive_value(obj):
217217
if obj is None:
218218
return False
219219
if isinstance(obj, (list, dict)):
220220
raise ValueError("query params may not contain repeated dicts or lists")
221221
return True
222222

223-
def _flatten_value(obj, key_path, strict=False): # pragma: NO COVER
223+
def _flatten_value(obj, key_path, strict=False):
224224
return [(".".join(key_path), _canonicalize(obj, strict=strict))]
225225

226-
def _flatten_dict(obj, key_path, strict=False): # pragma: NO COVER
226+
def _flatten_dict(obj, key_path, strict=False):
227227
items = (
228228
_flatten(value, key_path=key_path + [key], strict=strict)
229229
for key, value in obj.items()
230230
)
231231
return functools.reduce(operator.concat, items, [])
232232

233-
def _flatten_list(elems, key_path, strict=False): # pragma: NO COVER
233+
def _flatten_list(elems, key_path, strict=False):
234234
items = (
235235
_flatten_value(elem, key_path=key_path, strict=strict)
236236
for elem in elems
237237
if _is_primitive_value(elem)
238238
)
239239
return functools.reduce(operator.concat, items, [])
240240

241-
def _canonicalize(obj, strict=False): # pragma: NO COVER
241+
def _canonicalize(obj, strict=False):
242242
if strict:
243243
value = str(obj)
244244
if isinstance(obj, bool):
245245
value = value.lower()
246246
return value
247247
return obj
248248

249-
def transcode_request( # pragma: NO COVER
249+
def transcode_request(
250250
http_options: List[Dict[str, str]],
251251
request: Any,
252252
required_fields_default_values: Optional[Dict[str, Any]] = None,
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# {% include '_license.j2' %}
2+
3+
import pytest
4+
import os
5+
from google.auth.exceptions import MutualTLSChannelError
6+
7+
{% set package_path = api.naming.module_namespace|join('.') + "." + api.naming.versioned_module_name %}
8+
from {{package_path}} import _compat
9+
10+
11+
def test_get_default_mtls_endpoint():
12+
assert _compat.get_default_mtls_endpoint(None) is None
13+
assert _compat.get_default_mtls_endpoint("foo.googleapis.com") == "foo.mtls.googleapis.com"
14+
assert _compat.get_default_mtls_endpoint("foo.sandbox.googleapis.com") == "foo.mtls.sandbox.googleapis.com"
15+
assert _compat.get_default_mtls_endpoint("foo.mtls.googleapis.com") == "foo.mtls.googleapis.com"
16+
assert _compat.get_default_mtls_endpoint("invalid") == "invalid"
17+
18+
19+
def test_get_api_endpoint():
20+
assert _compat.get_api_endpoint("https://override.com", None, "googleapis.com", "auto", "googleapis.com", "mtls.com", "https://{UNIVERSE_DOMAIN}") == "https://override.com"
21+
assert _compat.get_api_endpoint(None, lambda: (b"", b""), "googleapis.com", "always", "googleapis.com", "mtls.com", "https://{UNIVERSE_DOMAIN}") == "mtls.com"
22+
with pytest.raises(MutualTLSChannelError):
23+
_compat.get_api_endpoint(None, None, "otheruniverse.com", "always", "googleapis.com", "mtls.com", "https://{UNIVERSE_DOMAIN}")
24+
assert _compat.get_api_endpoint(None, None, "googleapis.com", "never", "googleapis.com", "mtls.com", "https://{UNIVERSE_DOMAIN}") == "https://googleapis.com"
25+
26+
27+
def test_get_universe_domain():
28+
assert _compat.get_universe_domain("custom.com", None, "googleapis.com") == "custom.com"
29+
assert _compat.get_universe_domain(None, "env.com", "googleapis.com") == "env.com"
30+
assert _compat.get_universe_domain(None, None, "googleapis.com") == "googleapis.com"
31+
with pytest.raises(ValueError):
32+
_compat.get_universe_domain(" ", None, "googleapis.com")
33+
34+
35+
def test_use_client_cert_effective(monkeypatch):
36+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "true")
37+
assert _compat.use_client_cert_effective() is True
38+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false")
39+
assert _compat.use_client_cert_effective() is False
40+
monkeypatch.setenv("GOOGLE_API_USE_CLIENT_CERTIFICATE", "invalid")
41+
with pytest.raises(ValueError):
42+
_compat.use_client_cert_effective()
43+
44+
45+
def test_get_client_cert_source():
46+
cert_fn = lambda: (b"cert", b"key")
47+
assert _compat.get_client_cert_source(cert_fn, True) == cert_fn
48+
assert _compat.get_client_cert_source(None, False) is None
49+
with pytest.raises(ValueError):
50+
_compat.get_client_cert_source(None, True)
51+
52+
53+
def test_read_environment_variables(monkeypatch):
54+
monkeypatch.setenv("GOOGLE_API_USE_MTLS_ENDPOINT", "always")
55+
monkeypatch.setenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN", "myuniverse.com")
56+
use_cert, use_mtls, universe = _compat.read_environment_variables()
57+
assert use_mtls == "always"
58+
assert universe == "myuniverse.com"
59+
60+
monkeypatch.setenv("GOOGLE_API_USE_MTLS_ENDPOINT", "invalid")
61+
with pytest.raises(MutualTLSChannelError):
62+
_compat.read_environment_variables()
63+
64+
65+
def test_setup_request_id():
66+
# Test with None request
67+
_compat.setup_request_id(None, "request_id", False)
68+
69+
# Test with dict request (proto3 optional and non-optional)
70+
d1 = {}
71+
_compat.setup_request_id(d1, "request_id", is_proto3_optional=True)
72+
assert "request_id" in d1
73+
74+
d2 = {}
75+
_compat.setup_request_id(d2, "request_id", is_proto3_optional=False)
76+
assert "request_id" in d2
77+
78+
# Test when field already present
79+
d3 = {"request_id": "existing"}
80+
_compat.setup_request_id(d3, "request_id", is_proto3_optional=False)
81+
assert d3["request_id"] == "existing"
82+
83+
# Test with object
84+
class Dummy:
85+
request_id = None
86+
obj = Dummy()
87+
_compat.setup_request_id(obj, "request_id", is_proto3_optional=False)
88+
assert obj.request_id is not None
89+
90+
91+
def test_flatten_query_params():
92+
assert _compat.flatten_query_params(None) == []
93+
res = _compat.flatten_query_params({"a": "val1", "b": [1, 2]})
94+
assert ("a", "val1") in res
95+
assert ("b", 1) in res
96+
assert ("b", 2) in res
97+
98+
with pytest.raises(TypeError):
99+
_compat.flatten_query_params("invalid")
100+
101+
with pytest.raises(ValueError):
102+
_compat.flatten_query_params({"a": [{"nested": "dict"}]})

packages/gapic-generator/tests/integration/goldens/asset/google/cloud/asset_v1/_compat.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
get_api_endpoint,
3333
get_universe_domain,
3434
)
35-
except ImportError: # pragma: NO COVER
35+
except ImportError:
3636
# TODO(https://github.com/googleapis/google-cloud-python/issues/17813): Universe domain support was introduced in google-api-core 2.18.0.
3737
# Remove these fallback definitions when google-api-core >= 2.18.0 becomes the minimum required version in generated client setup dependencies.
3838
def get_default_mtls_endpoint(api_endpoint: Optional[str]) -> Optional[str]:
@@ -104,7 +104,7 @@ def get_universe_domain(
104104
get_client_cert_source,
105105
read_environment_variables,
106106
)
107-
except ImportError: # pragma: NO COVER
107+
except ImportError:
108108
from google.auth.transport import mtls # type: ignore
109109

110110
# TODO(https://github.com/googleapis/google-cloud-python/issues/17813): Remove these fallbacks when google-api-core >= 2.18.0 is the minimum required version.
@@ -157,7 +157,7 @@ def read_environment_variables() -> Tuple[bool, str, Optional[str]]:
157157

158158
try:
159159
from google.api_core.gapic_v1.request import setup_request_id # type: ignore
160-
except ImportError: # pragma: NO COVER
160+
except ImportError:
161161
# TODO(https://github.com/googleapis/google-cloud-python/issues/17813): Request ID setup helper was introduced in google-api-core 2.26.0.
162162
# Remove this fallback definition when google-api-core >= 2.26.0 becomes the minimum required version in generated client setup dependencies.
163163
def setup_request_id(request, field_name: str, is_proto3_optional: bool):
@@ -207,17 +207,17 @@ def setup_request_id(request, field_name: str, is_proto3_optional: bool):
207207
flatten_query_params,
208208
transcode_request,
209209
)
210-
except ImportError: # pragma: NO COVER
210+
except ImportError:
211211
# TODO: Remove these fallbacks when google-api-core >= 2.18.0 is the minimum required version.
212212
from google.protobuf import json_format # type: ignore
213213
from google.api_core import path_template # type: ignore
214214

215-
def flatten_query_params(obj, strict=False): # pragma: NO COVER
215+
def flatten_query_params(obj, strict=False):
216216
if obj is not None and not isinstance(obj, dict):
217217
raise TypeError("flatten_query_params must be called with dict object")
218218
return _flatten(obj, key_path=[], strict=strict)
219219

220-
def _flatten(obj, key_path, strict=False): # pragma: NO COVER
220+
def _flatten(obj, key_path, strict=False):
221221
if obj is None:
222222
return []
223223
if isinstance(obj, dict):
@@ -226,40 +226,40 @@ def _flatten(obj, key_path, strict=False): # pragma: NO COVER
226226
return _flatten_list(obj, key_path=key_path, strict=strict)
227227
return _flatten_value(obj, key_path=key_path, strict=strict)
228228

229-
def _is_primitive_value(obj): # pragma: NO COVER
229+
def _is_primitive_value(obj):
230230
if obj is None:
231231
return False
232232
if isinstance(obj, (list, dict)):
233233
raise ValueError("query params may not contain repeated dicts or lists")
234234
return True
235235

236-
def _flatten_value(obj, key_path, strict=False): # pragma: NO COVER
236+
def _flatten_value(obj, key_path, strict=False):
237237
return [(".".join(key_path), _canonicalize(obj, strict=strict))]
238238

239-
def _flatten_dict(obj, key_path, strict=False): # pragma: NO COVER
239+
def _flatten_dict(obj, key_path, strict=False):
240240
items = (
241241
_flatten(value, key_path=key_path + [key], strict=strict)
242242
for key, value in obj.items()
243243
)
244244
return functools.reduce(operator.concat, items, [])
245245

246-
def _flatten_list(elems, key_path, strict=False): # pragma: NO COVER
246+
def _flatten_list(elems, key_path, strict=False):
247247
items = (
248248
_flatten_value(elem, key_path=key_path, strict=strict)
249249
for elem in elems
250250
if _is_primitive_value(elem)
251251
)
252252
return functools.reduce(operator.concat, items, [])
253253

254-
def _canonicalize(obj, strict=False): # pragma: NO COVER
254+
def _canonicalize(obj, strict=False):
255255
if strict:
256256
value = str(obj)
257257
if isinstance(obj, bool):
258258
value = value.lower()
259259
return value
260260
return obj
261261

262-
def transcode_request( # pragma: NO COVER
262+
def transcode_request(
263263
http_options: List[Dict[str, str]],
264264
request: Any,
265265
required_fields_default_values: Optional[Dict[str, Any]] = None,

0 commit comments

Comments
 (0)