Skip to content

Commit 60b2bfa

Browse files
committed
update post processing script for spanner
1 parent 04bbea2 commit 60b2bfa

File tree

2 files changed

+140
-1
lines changed

2 files changed

+140
-1
lines changed

.librarian/generator-input/client-post-processing/spanner-integration.yaml

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,77 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
description: Integrate Google Cloud Spanner customizations for MetricsInterceptor and gRPC options
14+
description: Integrate Google Cloud Logging Spanner Handwritten code
1515
url: https://github.com/googleapis/gapic-generator-python/issues/123
16+
replacements:
17+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/client.py]
18+
before: '(import google\.rpc\.status_pb2 as status_pb2 # type: ignore\n\n)(?!from google\.cloud\.spanner_v1\.metrics)'
19+
after: |
20+
\g<1>from google.cloud.spanner_v1.metrics.metrics_interceptor import MetricsInterceptor
21+
count: 1
22+
23+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/client.py]
24+
before: '(\s+api_audience=self\._client_options\.api_audience,\n)(?!\s+metrics_interceptor=MetricsInterceptor)'
25+
after: |
26+
\g<1> metrics_interceptor=MetricsInterceptor(),
27+
count: 1
28+
29+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/base.py]
30+
before: '(from google\.cloud\.spanner_v1 import gapic_version as package_version\n)(?!from google\.cloud\.spanner_v1\.metrics)'
31+
after: |
32+
\g<1>from google.cloud.spanner_v1.metrics.metrics_interceptor import MetricsInterceptor
33+
count: 1
34+
35+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/rest.py]
36+
before: '(from requests import __version__ as requests_version\n\n)(?!from google\.cloud\.spanner_v1\.metrics)'
37+
after: |
38+
\g<1>from google.cloud.spanner_v1.metrics.metrics_interceptor import MetricsInterceptor
39+
count: 1
40+
41+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py]
42+
before: '(from grpc\.experimental import aio # type: ignore\n\n)(?!from google\.cloud\.spanner_v1\.metrics)'
43+
after: |
44+
\g<1>from google.cloud.spanner_v1.metrics.metrics_interceptor import MetricsInterceptor
45+
count: 1
46+
47+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc.py]
48+
before: '(from google\.protobuf\.json_format import MessageToJson\n\n)(?!from google\.cloud\.spanner_v1\.metrics)'
49+
after: |
50+
\g<1>from google.cloud.spanner_v1.metrics.metrics_interceptor import MetricsInterceptor
51+
count: 1
52+
53+
- paths: [packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/rest_base.py]
54+
before: '(from google\.protobuf import json_format\n\n)(?!from google\.cloud\.spanner_v1\.metrics)'
55+
after: |
56+
\g<1>from google.cloud.spanner_v1.metrics.metrics_interceptor import MetricsInterceptor
57+
count: 1
58+
59+
- paths:
60+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/base.py
61+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc.py
62+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py
63+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/rest.py
64+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/rest_base.py
65+
before: '(\s+api_audience: Optional\[str\] = None,\n)(?!\s+metrics_interceptor: Optional\[MetricsInterceptor\])'
66+
after: |
67+
\g<1> metrics_interceptor: Optional[MetricsInterceptor] = None,
68+
count: 5
69+
70+
- paths:
71+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc.py
72+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py
73+
- packages/google-cloud-spanner/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py
74+
- packages/google-cloud-spanner/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py
75+
- packages/google-cloud-spanner/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py
76+
- packages/google-cloud-spanner/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py
77+
before: '(\s+\("grpc\.max_receive_message_length", -1\),\n)(?!\s+\("grpc\.keepalive_time_ms")'
78+
after: |
79+
\g<1> ("grpc.keepalive_time_ms", 120000),
80+
count: 6
81+
82+
- paths:
83+
- packages/google-cloud-spanner/google/cloud/spanner_v1/services/spanner/transports/grpc.py
84+
before: '(\s+self\._stubs: Dict\[str, Callable\] = \{\}\n)(?!\s+self\._metrics_interceptor = None)'
85+
after: |
86+
\g<1> self._metrics_interceptor = None
87+
count: 1

verify_integration.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import re
2+
import yaml
3+
import os
4+
5+
def main():
6+
# Adjusted path to match your structure
7+
yaml_path = ".librarian/generator-input/client-post-processing/spanner-integration.yaml"
8+
9+
if not os.path.exists(yaml_path):
10+
print(f"❌ Error: YAML not found at {yaml_path}")
11+
return
12+
13+
with open(yaml_path, "r") as f:
14+
config = yaml.safe_load(f)
15+
replacements = config.get("replacements", [])
16+
17+
# Track which files actually exist locally
18+
all_paths = set()
19+
for r in replacements:
20+
for path in r.get("paths", []):
21+
all_paths.add(path)
22+
23+
for file_path in sorted(all_paths):
24+
if not os.path.exists(file_path):
25+
print(f"⏭️ Skipping: {file_path} (not found)")
26+
continue
27+
28+
with open(file_path, "r") as f:
29+
content = f.read()
30+
31+
working_content = content
32+
modified = False
33+
34+
print(f"\nPROCESSING: {file_path}")
35+
36+
# PASS 1: Apply replacements
37+
for i, r in enumerate(replacements):
38+
if file_path in r.get("paths", []):
39+
# We check if the 'before' pattern exists
40+
if re.search(r["before"], working_content, flags=re.MULTILINE):
41+
working_content = re.sub(r["before"], r["after"], working_content, flags=re.MULTILINE)
42+
modified = True
43+
print(f" [Pass 1] Block {i+1}: Applied.")
44+
else:
45+
print(f" [Pass 1] Block {i+1}: No match (already applied or pattern mismatch).")
46+
47+
if not modified:
48+
print(" No changes made.")
49+
continue
50+
51+
# PASS 2: Idempotency check (Should be 0 matches now)
52+
idempotent_fail = False
53+
for i, r in enumerate(replacements):
54+
if file_path in r.get("paths", []):
55+
if re.search(r["before"], working_content, flags=re.MULTILINE):
56+
print(f" [Pass 2] ❌ FAIL: Block {i+1} matched again. Fix lookahead logic!")
57+
idempotent_fail = True
58+
59+
if not idempotent_fail:
60+
with open(file_path, "w") as f:
61+
f.write(working_content)
62+
print(" ✅ SUCCESS: Disk updated and verified idempotent.")
63+
else:
64+
print(" ⚠️ WARNING: File NOT updated due to idempotency failure.")
65+
66+
if __name__ == "__main__":
67+
main()

0 commit comments

Comments
 (0)