gapic-generator 1.30.6__py3-none-any.whl → 1.30.7__py3-none-any.whl

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 (56) hide show
  1. gapic/cli/generate.py +1 -1
  2. gapic/generator/generator.py +1 -3
  3. gapic/samplegen_utils/snippet_index.py +3 -1
  4. gapic/samplegen_utils/yaml.py +3 -1
  5. gapic/schema/api.py +2 -7
  6. gapic/schema/metadata.py +1 -1
  7. gapic/schema/naming.py +1 -1
  8. gapic/schema/wrappers.py +1 -1
  9. gapic/templates/%namespace/%name_%version/%sub/services/%service/async_client.py.j2 +4 -2
  10. gapic/templates/noxfile.py.j2 +33 -15
  11. gapic/templates/tests/unit/gapic/%name_%version/%sub/test_%service.py.j2 +1 -0
  12. gapic/templates/tests/unit/gapic/%name_%version/%sub/test_macros.j2 +30 -0
  13. gapic/utils/cache.py +0 -1
  14. {gapic_generator-1.30.6.dist-info → gapic_generator-1.30.7.dist-info}/METADATA +1 -1
  15. {gapic_generator-1.30.6.dist-info → gapic_generator-1.30.7.dist-info}/RECORD +56 -56
  16. tests/integration/goldens/asset/google/cloud/asset_v1/services/asset_service/async_client.py +4 -2
  17. tests/integration/goldens/asset/noxfile.py +32 -15
  18. tests/integration/goldens/asset/tests/unit/gapic/asset_v1/test_asset_service.py +1 -0
  19. tests/integration/goldens/credentials/google/iam/credentials_v1/services/iam_credentials/async_client.py +4 -2
  20. tests/integration/goldens/credentials/noxfile.py +32 -15
  21. tests/integration/goldens/credentials/tests/unit/gapic/credentials_v1/test_iam_credentials.py +1 -0
  22. tests/integration/goldens/eventarc/google/cloud/eventarc_v1/services/eventarc/async_client.py +4 -2
  23. tests/integration/goldens/eventarc/noxfile.py +32 -15
  24. tests/integration/goldens/eventarc/tests/unit/gapic/eventarc_v1/test_eventarc.py +1 -0
  25. tests/integration/goldens/logging/google/cloud/logging_v2/services/config_service_v2/async_client.py +4 -2
  26. tests/integration/goldens/logging/google/cloud/logging_v2/services/logging_service_v2/async_client.py +4 -2
  27. tests/integration/goldens/logging/google/cloud/logging_v2/services/metrics_service_v2/async_client.py +4 -2
  28. tests/integration/goldens/logging/noxfile.py +32 -15
  29. tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_config_service_v2.py +1 -0
  30. tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_logging_service_v2.py +1 -0
  31. tests/integration/goldens/logging/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +1 -0
  32. tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/config_service_v2/async_client.py +4 -2
  33. tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/logging_service_v2/async_client.py +4 -2
  34. tests/integration/goldens/logging_internal/google/cloud/logging_v2/services/metrics_service_v2/async_client.py +4 -2
  35. tests/integration/goldens/logging_internal/noxfile.py +32 -15
  36. tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_config_service_v2.py +1 -0
  37. tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_logging_service_v2.py +1 -0
  38. tests/integration/goldens/logging_internal/tests/unit/gapic/logging_v2/test_metrics_service_v2.py +1 -0
  39. tests/integration/goldens/redis/google/cloud/redis_v1/services/cloud_redis/async_client.py +4 -2
  40. tests/integration/goldens/redis/noxfile.py +32 -15
  41. tests/integration/goldens/redis/tests/unit/gapic/redis_v1/test_cloud_redis.py +1 -0
  42. tests/integration/goldens/redis_selective/google/cloud/redis_v1/services/cloud_redis/async_client.py +4 -2
  43. tests/integration/goldens/redis_selective/noxfile.py +32 -15
  44. tests/integration/goldens/redis_selective/tests/unit/gapic/redis_v1/test_cloud_redis.py +1 -0
  45. tests/system/test_lro.py +0 -1
  46. tests/unit/common_types.py +1 -1
  47. tests/unit/generator/test_formatter.py +25 -40
  48. tests/unit/generator/test_generator.py +2 -2
  49. tests/unit/generator/test_options.py +1 -1
  50. tests/unit/schema/test_api.py +18 -18
  51. tests/unit/schema/wrappers/test_field.py +6 -6
  52. tests/unit/schema/wrappers/test_method.py +2 -1
  53. {gapic_generator-1.30.6.dist-info → gapic_generator-1.30.7.dist-info}/WHEEL +0 -0
  54. {gapic_generator-1.30.6.dist-info → gapic_generator-1.30.7.dist-info}/entry_points.txt +0 -0
  55. {gapic_generator-1.30.6.dist-info → gapic_generator-1.30.7.dist-info}/licenses/LICENSE +0 -0
  56. {gapic_generator-1.30.6.dist-info → gapic_generator-1.30.7.dist-info}/top_level.txt +0 -0
gapic/cli/generate.py CHANGED
@@ -39,7 +39,7 @@ from gapic.utils.cache import generation_cache_context
39
39
  "--output",
40
40
  type=click.File("wb"),
41
41
  default=sys.stdout.buffer,
42
- help="Where to output the `CodeGeneratorResponse`. " "Defaults to stdout.",
42
+ help="Where to output the `CodeGeneratorResponse`. Defaults to stdout.",
43
43
  )
44
44
  def generate(request: typing.BinaryIO, output: typing.BinaryIO) -> None:
45
45
  """Generate a full API client description."""
@@ -131,9 +131,7 @@ class Generator:
131
131
  )
132
132
 
133
133
  # Return the CodeGeneratorResponse output.
134
- res = CodeGeneratorResponse(
135
- file=[i for i in output_files.values()]
136
- ) # type: ignore
134
+ res = CodeGeneratorResponse(file=[i for i in output_files.values()]) # type: ignore
137
135
  res.supported_features |= CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL # type: ignore
138
136
  return res
139
137
 
@@ -117,7 +117,9 @@ class SnippetIndex:
117
117
  self.metadata_index.client_library.name = (
118
118
  api_schema.naming.warehouse_package_name
119
119
  )
120
- self.metadata_index.client_library.language = snippet_metadata_pb2.Language.PYTHON # type: ignore
120
+ self.metadata_index.client_library.language = (
121
+ snippet_metadata_pb2.Language.PYTHON # type: ignore
122
+ )
121
123
 
122
124
  self.metadata_index.client_library.version = api_schema.gapic_version
123
125
 
@@ -116,7 +116,9 @@ class Map(Element):
116
116
  return next(
117
117
  iter(
118
118
  [
119
- e.val for e in self.elements if e.key == key # type: ignore
119
+ e.val
120
+ for e in self.elements
121
+ if e.key == key # type: ignore
120
122
  ] # type: ignore
121
123
  ),
122
124
  default,
gapic/schema/api.py CHANGED
@@ -941,11 +941,7 @@ class API:
941
941
  selective_gapic_errors = {}
942
942
  # TODO(https://github.com/googleapis/gapic-generator-python/issues/2446):
943
943
  # Workaround issue in Python 3.14 related to code coverage by adding `# pragma: no branch`
944
- for (
945
- method_name
946
- ) in (
947
- library_settings.python_settings.common.selective_gapic_generation.methods
948
- ): # pragma: no branch
944
+ for method_name in library_settings.python_settings.common.selective_gapic_generation.methods: # pragma: no branch
949
945
  if method_name not in self.all_methods:
950
946
  selective_gapic_errors[method_name] = "Method does not exist."
951
947
  elif not method_name.startswith(library_settings.version):
@@ -1180,8 +1176,7 @@ class _ProtoBuilder:
1180
1176
  object.__setattr__(field, "enum", maybe_enum_type)
1181
1177
  else:
1182
1178
  raise TypeError(
1183
- f"Unknown type referenced in "
1184
- f"{self.file_descriptor.name}: '{key}'"
1179
+ f"Unknown type referenced in {self.file_descriptor.name}: '{key}'"
1185
1180
  )
1186
1181
 
1187
1182
  # Only generate the service if this is a target file to be generated.
gapic/schema/metadata.py CHANGED
@@ -357,7 +357,7 @@ class Address(BaseAddress):
357
357
  str: An absolute selector.
358
358
  """
359
359
  if "." not in selector:
360
- return f'{".".join(self.package)}.{selector}'
360
+ return f"{'.'.join(self.package)}.{selector}"
361
361
  return selector
362
362
 
363
363
  @cached_proto_context
gapic/schema/naming.py CHANGED
@@ -86,7 +86,7 @@ class Naming(abc.ABC):
86
86
  "The protos provided do not share a common root package. "
87
87
  "Ensure that all explicitly-specified protos are for a "
88
88
  "single API. "
89
- f'The packages we got are: {", ".join(proto_packages)}'
89
+ f"The packages we got are: {', '.join(proto_packages)}"
90
90
  )
91
91
 
92
92
  # Define the valid regex to split the package.
gapic/schema/wrappers.py CHANGED
@@ -799,7 +799,7 @@ class MessageType:
799
799
  # Quick check: If this cursor has no message, there is a problem.
800
800
  if not cursor.message:
801
801
  raise KeyError(
802
- f'Field {".".join(field_path)} could not be resolved from '
802
+ f"Field {'.'.join(field_path)} could not be resolved from "
803
803
  f"{cursor.name}.",
804
804
  )
805
805
 
@@ -98,7 +98,8 @@ class {{ service.async_client_name }}:
98
98
  Returns:
99
99
  {{ service.async_client_name }}: The constructed client.
100
100
  """
101
- return {{ service.client_name }}.from_service_account_info.__func__({{ service.async_client_name }}, info, *args, **kwargs) # type: ignore
101
+ sa_info_func = {{ service.client_name }}.from_service_account_info.__func__ # type: ignore
102
+ return sa_info_func({{ service.async_client_name }}, info, *args, **kwargs)
102
103
 
103
104
  @classmethod
104
105
  def from_service_account_file(cls, filename: str, *args, **kwargs):
@@ -114,7 +115,8 @@ class {{ service.async_client_name }}:
114
115
  Returns:
115
116
  {{ service.async_client_name }}: The constructed client.
116
117
  """
117
- return {{ service.client_name }}.from_service_account_file.__func__({{ service.async_client_name }}, filename, *args, **kwargs) # type: ignore
118
+ sa_file_func = {{ service.client_name }}.from_service_account_file.__func__ # type: ignore
119
+ return sa_file_func({{ service.async_client_name }}, filename, *args, **kwargs)
118
120
 
119
121
  from_service_account_json = from_service_account_file
120
122
 
@@ -12,8 +12,7 @@ import warnings
12
12
 
13
13
  import nox
14
14
 
15
- BLACK_VERSION = "black[jupyter]==23.7.0"
16
- ISORT_VERSION = "isort==5.11.0"
15
+ RUFF_VERSION = "ruff==0.14.14"
17
16
 
18
17
  {% if api.naming.module_namespace %}
19
18
  LINT_PATHS = ["docs", "{{ api.naming.module_namespace[0] }}", "tests", "noxfile.py", "setup.py"]
@@ -147,13 +146,18 @@ def lint(session):
147
146
  Returns a failure if the linters find linting errors or sufficiently
148
147
  serious code quality issues.
149
148
  """
150
- session.install("flake8", BLACK_VERSION)
149
+ session.install("flake8", RUFF_VERSION)
150
+
151
+ # 2. Check formatting
151
152
  session.run(
152
- "black",
153
+ "ruff", "format",
153
154
  "--check",
155
+ f"--target-version=py{ALL_PYTHON[0].replace('.', '')}",
156
+ "--line-length=88",
154
157
  *LINT_PATHS,
155
158
  )
156
159
 
160
+
157
161
  {% if api.naming.module_namespace %}
158
162
  session.run("flake8", "{{ api.naming.module_namespace[0] }}", "tests")
159
163
  {% else %}
@@ -163,10 +167,15 @@ def lint(session):
163
167
 
164
168
  @nox.session(python=DEFAULT_PYTHON_VERSION)
165
169
  def blacken(session):
166
- """Run black. Format code to uniform standard."""
167
- session.install(BLACK_VERSION)
170
+ """(Deprecated) Legacy session. Please use 'nox -s format'."""
171
+ session.log("WARNING: The 'blacken' session is deprecated and will be removed in a future release. Please use 'nox -s format' in the future.")
172
+
173
+ # Just run the ruff formatter (keeping legacy behavior of only formatting, not sorting imports)
174
+ session.install(RUFF_VERSION)
168
175
  session.run(
169
- "black",
176
+ "ruff", "format",
177
+ f"--target-version=py{ALL_PYTHON[0].replace('.', '')}",
178
+ "--line-length=88",
170
179
  *LINT_PATHS,
171
180
  )
172
181
 
@@ -174,19 +183,28 @@ def blacken(session):
174
183
  @nox.session(python=DEFAULT_PYTHON_VERSION)
175
184
  def format(session):
176
185
  """
177
- Run isort to sort imports. Then run black
178
- to format code to uniform standard.
186
+ Run ruff to sort imports and format code.
179
187
  """
180
- session.install(BLACK_VERSION, ISORT_VERSION)
181
- # Use the --fss option to sort imports using strict alphabetical order.
182
- # See https://pycqa.github.io/isort/docs/configuration/options.html#force-sort-within-sections
188
+ # 1. Install ruff (skipped automatically if you run with --no-venv)
189
+ session.install(RUFF_VERSION)
190
+
191
+ # 2. Run Ruff to fix imports
192
+ # check --select I: Enables strict import sorting
193
+ # --fix: Applies the changes automatically
183
194
  session.run(
184
- "isort",
185
- "--fss",
195
+ "ruff", "check",
196
+ "--select", "I",
197
+ "--fix",
198
+ f"--target-version=py{ALL_PYTHON[0].replace('.', '')}",
199
+ "--line-length=88", # Standard Black line length
186
200
  *LINT_PATHS,
187
201
  )
202
+
203
+ # 3. Run Ruff to format code
188
204
  session.run(
189
- "black",
205
+ "ruff", "format",
206
+ f"--target-version=py{ALL_PYTHON[0].replace('.', '')}",
207
+ "--line-length=88", # Standard Black line length
190
208
  *LINT_PATHS,
191
209
  )
192
210
 
@@ -26,6 +26,7 @@ from google.protobuf import json_format
26
26
  import json
27
27
  import math
28
28
  import pytest
29
+ from collections.abc import Sequence, Mapping
29
30
  from google.api_core import api_core_version
30
31
  from proto.marshal.rules.dates import DurationRule, TimestampRule
31
32
  from proto.marshal.rules import wrappers
@@ -752,8 +752,18 @@ def test_{{ method_name }}_pager(transport_name: str = "grpc"):
752
752
 
753
753
  results = list(pager)
754
754
  assert len(results) == 6
755
+ {% if method.paged_result_field.type.ident|string == 'struct_pb2.ListValue' %}
756
+ assert all(isinstance(i, Sequence)
757
+ for i in results)
758
+ {% elif method.paged_result_field.type.ident|string == 'struct_pb2.Struct' %}
759
+ assert all(isinstance(i, Mapping)
760
+ for i in results)
761
+ {% elif method.paged_result_field.type.ident|string == 'struct_pb2.Value' %}
762
+ assert all(True for i in results)
763
+ {% else %}
755
764
  assert all(isinstance(i, {{ method.paged_result_field.type.ident }})
756
765
  for i in results)
766
+ {% endif %}
757
767
  {% endif %}
758
768
  def test_{{ method_name }}_pages(transport_name: str = "grpc"):
759
769
  client = {{ service.client_name }}(
@@ -913,9 +923,19 @@ async def test_{{ method_name }}_async_pager():
913
923
  assert async_pager.get('a') is None
914
924
  assert isinstance(async_pager.get('h'), {{ method.paged_result_field.type.fields.get('value').ident }})
915
925
  {% else %}
926
+ {% if method.paged_result_field.type.ident|string == 'struct_pb2.ListValue' %}
927
+ assert all(isinstance(i, Sequence)
928
+ for i in responses)
929
+ {% elif method.paged_result_field.type.ident|string == 'struct_pb2.Struct' %}
930
+ assert all(isinstance(i, Mapping)
931
+ for i in responses)
932
+ {% elif method.paged_result_field.type.ident|string == 'struct_pb2.Value' %}
933
+ assert all(True for i in responses)
934
+ {% else %}
916
935
  assert all(isinstance(i, {{ method.paged_result_field.type.ident }})
917
936
  for i in responses)
918
937
  {% endif %}
938
+ {% endif %}
919
939
 
920
940
 
921
941
  @pytest.mark.asyncio
@@ -1412,9 +1432,19 @@ def test_{{ method_name }}_rest_pager(transport: str = 'rest'):
1412
1432
  assert pager.get('a') is None
1413
1433
  assert isinstance(pager.get('h'), {{ method.paged_result_field.type.fields.get('value').ident }})
1414
1434
  {% else %}
1435
+ {% if method.paged_result_field.type.ident|string == 'struct_pb2.ListValue' %}
1436
+ assert all(isinstance(i, Sequence)
1437
+ for i in results)
1438
+ {% elif method.paged_result_field.type.ident|string == 'struct_pb2.Struct' %}
1439
+ assert all(isinstance(i, Mapping)
1440
+ for i in results)
1441
+ {% elif method.paged_result_field.type.ident|string == 'struct_pb2.Value' %}
1442
+ assert all(True for i in results)
1443
+ {% else %}
1415
1444
  assert all(isinstance(i, {{ method.paged_result_field.type.ident }})
1416
1445
  for i in results)
1417
1446
  {% endif %}
1447
+ {% endif %}
1418
1448
 
1419
1449
  pages = list(client.{{ method_name }}(request=sample_request).pages)
1420
1450
  for page_, token in zip(pages, ['abc','def','ghi', '']):
gapic/utils/cache.py CHANGED
@@ -101,7 +101,6 @@ def cached_proto_context(func):
101
101
 
102
102
  @functools.wraps(func)
103
103
  def wrapper(self, *, collisions, **kwargs):
104
-
105
104
  # 1. Check for active cache (returns None if context is not active)
106
105
  context_cache = getattr(
107
106
  _proto_collisions_cache_state, "resolved_collisions", None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gapic-generator
3
- Version: 1.30.6
3
+ Version: 1.30.7
4
4
  Summary: Google API Client Generator for Python
5
5
  Home-page: https://github.com/googleapis/gapic-generator-python
6
6
  Author: Google LLC