Skip to content

Commit a68d207

Browse files
committed
chore: use ruff based code formatting
1 parent 90b6c51 commit a68d207

244 files changed

Lines changed: 26856 additions & 43254 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.generator/cli.py

Lines changed: 93 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import subprocess
2424
import sys
2525
import tempfile
26+
import time
2627
import yaml
2728
from datetime import date, datetime
2829
from functools import lru_cache
@@ -31,6 +32,40 @@
3132
import build.util
3233
import parse_googleapis_content
3334

35+
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
36+
37+
import functools
38+
39+
PERF_LOGGING_ENABLED = os.environ.get("ENABLE_PERF_LOGS") == "1"
40+
41+
if PERF_LOGGING_ENABLED:
42+
perf_logger = logging.getLogger("performance_metrics")
43+
perf_logger.setLevel(logging.INFO)
44+
perf_handler = logging.FileHandler("/tmp/performance_metrics.log", mode='w')
45+
perf_formatter = logging.Formatter('%(asctime)s | %(message)s', datefmt='%H:%M:%S')
46+
perf_handler.setFormatter(perf_formatter)
47+
perf_logger.addHandler(perf_handler)
48+
perf_logger.propagate = False
49+
50+
def track_time(func):
51+
"""
52+
Decorator. Usage: @track_time
53+
If logging is OFF, it returns the original function (Zero Overhead).
54+
If logging is ON, it wraps the function to measure execution time.
55+
"""
56+
if not PERF_LOGGING_ENABLED:
57+
return func
58+
59+
@functools.wraps(func)
60+
def wrapper(*args, **kwargs):
61+
start_time = time.perf_counter()
62+
try:
63+
return func(*args, **kwargs)
64+
finally:
65+
duration = time.perf_counter() - start_time
66+
perf_logger.info(f"{func.__name__:<30} | {duration:.4f} seconds")
67+
68+
return wrapper
3469

3570
try:
3671
import synthtool
@@ -323,8 +358,9 @@ def _get_library_id(request_data: Dict) -> str:
323358
return library_id
324359

325360

361+
@track_time
326362
def _run_post_processor(output: str, library_id: str, is_mono_repo: bool):
327-
"""Runs the synthtool post-processor on the output directory.
363+
"""Runs the synthtool post-processor (templates) and Ruff formatter (lint/format).
328364
329365
Args:
330366
output(str): Path to the directory in the container where code
@@ -334,25 +370,58 @@ def _run_post_processor(output: str, library_id: str, is_mono_repo: bool):
334370
"""
335371
os.chdir(output)
336372
path_to_library = f"packages/{library_id}" if is_mono_repo else "."
337-
logger.info("Running Python post-processor...")
373+
374+
# 1. Run Synthtool (Templates & Fixers only)
375+
# Note: This relies on 'nox' being disabled in your environment (via run_fast.sh shim)
376+
# to avoid the slow formatting step inside owlbot.
377+
logger.info("Running Python post-processor (Templates & Fixers)...")
338378
if SYNTHTOOL_INSTALLED:
339-
if is_mono_repo:
340-
python_mono_repo.owlbot_main(path_to_library)
341-
else:
342-
# Some repositories have customizations in `librarian.py`.
343-
# If this file exists, run those customizations instead of `owlbot_main`
344-
if Path(f"{output}/librarian.py").exists():
345-
subprocess.run(["python3.14", f"{output}/librarian.py"])
379+
try:
380+
if is_mono_repo:
381+
python_mono_repo.owlbot_main(path_to_library)
346382
else:
347-
python.owlbot_main()
348-
else:
349-
raise SYNTHTOOL_IMPORT_ERROR # pragma: NO COVER
383+
# Handle custom librarian scripts if present
384+
if Path(f"{output}/librarian.py").exists():
385+
subprocess.run(["python3.14", f"{output}/librarian.py"])
386+
else:
387+
python.owlbot_main()
388+
except Exception as e:
389+
logger.warning(f"Synthtool warning (non-fatal): {e}")
390+
391+
# 2. Run RUFF (Fast Formatter & Import Sorter)
392+
# This replaces both 'isort' and 'black' and runs in < 1 second.
393+
# We hardcode flags here to match Black defaults so you don't need config files.
394+
# logger.info("🚀 Running Ruff (Fast Formatter)...")
395+
try:
396+
# STEP A: Fix Imports (like isort)
397+
subprocess.run(
398+
[
399+
"ruff", "check",
400+
"--select", "I", # Only run Import sorting rules
401+
"--fix", # Auto-fix them
402+
"--line-length=88", # Match Black default
403+
"--known-first-party=google", # Prevent 'google' moving to 3rd party block
404+
output
405+
],
406+
check=False,
407+
stdout=subprocess.DEVNULL,
408+
stderr=subprocess.DEVNULL
409+
)
350410

351-
# If there is no noxfile, run `isort`` and `black` on the output.
352-
# This is required for proto-only libraries which are not GAPIC.
353-
if not Path(f"{output}/{path_to_library}/noxfile.py").exists():
354-
subprocess.run(["isort", output])
355-
subprocess.run(["black", output])
411+
# STEP B: Format Code (like black)
412+
subprocess.run(
413+
[
414+
"ruff", "format",
415+
"--line-length=88", # Match Black default
416+
output
417+
],
418+
check=False,
419+
stdout=subprocess.DEVNULL,
420+
stderr=subprocess.DEVNULL
421+
)
422+
except FileNotFoundError:
423+
logger.warning("⚠️ Ruff binary not found. Code will be unformatted.")
424+
logger.warning(" Please run: pip install ruff")
356425

357426
logger.info("Python post-processor ran successfully.")
358427

@@ -392,6 +461,7 @@ def _add_header_to_files(directory: str) -> None:
392461
f.writelines(lines)
393462

394463

464+
@track_time
395465
def _copy_files_needed_for_post_processing(
396466
output: str, input: str, library_id: str, is_mono_repo: bool
397467
):
@@ -444,6 +514,7 @@ def _copy_files_needed_for_post_processing(
444514
)
445515

446516

517+
@track_time
447518
def _clean_up_files_after_post_processing(
448519
output: str, library_id: str, is_mono_repo: bool
449520
):
@@ -590,6 +661,7 @@ def _get_repo_name_from_repo_metadata(base: str, library_id: str, is_mono_repo:
590661
return repo_name
591662

592663

664+
@track_time
593665
def _generate_repo_metadata_file(
594666
output: str, library_id: str, source: str, apis: List[Dict], is_mono_repo: bool
595667
):
@@ -631,6 +703,7 @@ def _generate_repo_metadata_file(
631703
_write_json_file(output_repo_metadata, metadata_content)
632704

633705

706+
@track_time
634707
def _copy_readme_to_docs(output: str, library_id: str, is_mono_repo: bool):
635708
"""Copies the README.rst file for a generated library to docs/README.rst.
636709
@@ -672,6 +745,7 @@ def _copy_readme_to_docs(output: str, library_id: str, is_mono_repo: bool):
672745
f.write(content)
673746

674747

748+
@track_time
675749
def handle_generate(
676750
librarian: str = LIBRARIAN_DIR,
677751
source: str = SOURCE_DIR,
@@ -933,6 +1007,7 @@ def _stage_gapic_library(tmp_dir: str, staging_dir: str) -> None:
9331007
shutil.copytree(tmp_dir, staging_dir, dirs_exist_ok=True)
9341008

9351009

1010+
@track_time
9361011
def _generate_api(
9371012
api_path: str,
9381013
library_id: str,
@@ -1748,6 +1823,7 @@ def handle_release_stage(
17481823
output=args.output,
17491824
input=args.input,
17501825
)
1826+
17511827
elif args.command == "build":
17521828
args.func(librarian=args.librarian, repo=args.repo)
17531829
elif args.command == "release-stage":

.generator/requirements.in

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ gapic-generator==1.30.3 # Fix mypy checks https://github.com/googleapis/gapic-ge
33
nox
44
starlark-pyo3>=2025.1
55
build
6-
black==23.7.0
7-
isort==5.11.0
6+
ruff

.librarian/generate-request.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"id": "google-cloud-vision",
3+
"version": "3.12.0",
4+
"apis": [
5+
{
6+
"path": "google/cloud/vision/v1p3beta1",
7+
"service_config": "vision_v1p3beta1.yaml"
8+
},
9+
{
10+
"path": "google/cloud/vision/v1",
11+
"service_config": "vision_v1.yaml"
12+
},
13+
{
14+
"path": "google/cloud/vision/v1p1beta1",
15+
"service_config": "vision_v1p1beta1.yaml"
16+
},
17+
{
18+
"path": "google/cloud/vision/v1p2beta1",
19+
"service_config": "vision_v1p2beta1.yaml"
20+
},
21+
{
22+
"path": "google/cloud/vision/v1p4beta1",
23+
"service_config": "vision_v1p4beta1.yaml"
24+
}
25+
],
26+
"source_roots": [
27+
"packages/google-cloud-vision"
28+
],
29+
"preserve_regex": [
30+
"packages/google-cloud-vision/CHANGELOG.md",
31+
"docs/CHANGELOG.md",
32+
"samples/README.txt",
33+
"samples/snippets/README.rst",
34+
"tests/system"
35+
],
36+
"remove_regex": [
37+
"packages/google-cloud-vision/"
38+
],
39+
"tag_format": "{id}-v{version}"
40+
}

packages/google-cloud-vision/docs/conf.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
# All configuration values have a default; values that are commented out
2626
# serve to show the default.
2727

28+
import sys
2829
import os
2930
import shlex
30-
import sys
3131

3232
# If extensions (or modules to document with autodoc) are in another directory,
3333
# add these directories to sys.path here. If the directory is relative to the
@@ -81,9 +81,9 @@
8181
root_doc = "index"
8282

8383
# General information about the project.
84-
project = "google-cloud-vision"
85-
copyright = "2025, Google, LLC"
86-
author = "Google APIs"
84+
project = u"google-cloud-vision"
85+
copyright = u"2025, Google, LLC"
86+
author = u"Google APIs"
8787

8888
# The version info for the project you're documenting, acts as replacement for
8989
# |version| and |release|, also used in various other places throughout the
@@ -283,7 +283,7 @@
283283
(
284284
root_doc,
285285
"google-cloud-vision.tex",
286-
"google-cloud-vision Documentation",
286+
u"google-cloud-vision Documentation",
287287
author,
288288
"manual",
289289
)

0 commit comments

Comments
 (0)