Skip to content

Commit 8a1270c

Browse files
authored
feat: implement native PEP 0810 lazy loading (#17591)
## Overview This is an initiative to resolve severe initialization bottlenecks (~10s-13s) in generated client libraries by adopting **Native Python 3.15 Explicit Lazy Imports (PEP 0810)**. To avoid introducing maintenance burdens or subtle breaking changes via custom import hooks, this PR focuses *exclusively* on utilizing native interpreter standards. ### Implementation Architecture We modify the upstream GAPIC Generator to emit a native `__lazy_modules__` set at the top of the `__init__.py` files, immediately followed by the standard eager imports. * **Python 3.15+ (Native Acceleration):** The Python 3.15 runtime natively intercepts the standard imports referenced in the `__lazy_modules__` set and treats them as fast C-level lazy proxies. Startup times drop from ~13s to ~200ms, and peak RAM consumption drops by up to 85%. * **Python 3.14 and Older (Zero Blast Radius):** Older Python environments safely ignore the `__lazy_modules__` variable and process the standard eager imports exactly as they do today. This guarantees 100% backwards compatibility with zero risk. * **Perfect Static Typing:** Because standard imports are still present in the file, IDEs (IntelliSense) and static analyzers (MyPy) maintain zero-friction support. **Example Structure:** ```python # 1. Native C-Level Lazy Proxying for Python 3.15+ (PEP 0810) __lazy_modules__ = { f"{__name__}.services.accelerator_types", f"{__name__}.services.addresses", f"{__name__}.types.compute", } # 2. Standard eager imports # Evaluated instantly by older Python versions. Intercepted natively by Python 3.15. from .services.accelerator_types import AcceleratorTypesClient from .services.addresses import AddressesClient from .types.compute import Address __all__ = ( "AcceleratorTypesClient", "AddressesClient", "Address", ) ``` ## 🚀 Performance Benchmarking Results (Disk-Level Cold Start) We utilized our custom `profiler.py` script #17467 to run 5 iterations measuring true disk-level cold starts (with `__pycache__` sweeps) on the `google-cloud-compute` library. The results validate this Phase 1 PEP 810 Native Lazy Loading implementation: ### Python 3.14 (Current Eager Import) * **Time (Median):** `23,246.97 ms` (~23.2 seconds) * **Memory (Physical RSS):** `224.87 MB` * **Code Volume:** Loaded `1,407` modules (`1,040,992` lines of code) ### Python 3.15.0b2 (Phase 1 PEP 810 Lazy Proxy) * **Time (Median):** `1,062.87 ms` (~1.06 seconds) * **Memory (Physical RSS):** `7.21 MB` * **Code Volume:** Loaded `15` modules (`8,064` lines of code) **Impact:** By natively deferring the 120+ submodules at the C-level, we bypassed parsing over **1 million lines of code**. This resulted in an **approximately 22x reduction in startup latency (~95% speedup)**, and a staggering **96% reduction in peak RAM consumption** (dropping from ~225MB down to just ~7MB). Related Links: see #17594 for a demonstration of this generator change applied to google-cloud-compute package. Design Doc: go/sdk-performance-design Towards googleapis/python-aiplatform#4749
1 parent 2ddcf4d commit 8a1270c

9 files changed

Lines changed: 135 additions & 0 deletions

File tree

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,28 @@ __version__ = package_version.__version__
1212

1313
from importlib import metadata
1414

15+
# PEP 0810: Explicit Lazy Imports
16+
# Python 3.15+ natively intercepts and defers these imports.
17+
# Developers can disable this behavior and force eager imports.
18+
# For more information, see:
19+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
20+
# Older Python versions safely ignore this variable.
21+
__lazy_modules__ = {
22+
{% filter sort_lines -%}
23+
{% for subpackage, _ in api.subpackages|dictsort -%}
24+
f"{__name__}.{{ subpackage }}",
25+
{% endfor -%}
26+
{% for service in api.services.values()
27+
if service.meta.address.subpackage == api.subpackage_view -%}
28+
f"{__name__}.services.{{ service.name|snake_case }}",
29+
{% endfor -%}
30+
{% for proto in api.protos.values()
31+
if proto.meta.address.subpackage == api.subpackage_view -%}
32+
f"{__name__}.types.{{ proto.module_name }}",
33+
{% endfor -%}
34+
{% endfilter %}
35+
}
36+
1537
{# Import subpackages. -#}
1638
{% for subpackage, _ in api.subpackages|dictsort %}
1739
from . import {{ subpackage }}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.asset_service",
33+
f"{__name__}.types.asset_enrichment_resourceowners",
34+
f"{__name__}.types.asset_service",
35+
f"{__name__}.types.assets",
36+
}
37+
2538

2639
from .services.asset_service import AssetServiceClient
2740
from .services.asset_service import AssetServiceAsyncClient

packages/gapic-generator/tests/integration/goldens/credentials/google/iam/credentials_v1/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.iam_credentials",
33+
f"{__name__}.types.common",
34+
f"{__name__}.types.iamcredentials",
35+
}
36+
2537

2638
from .services.iam_credentials import IAMCredentialsClient
2739
from .services.iam_credentials import IAMCredentialsAsyncClient

packages/gapic-generator/tests/integration/goldens/eventarc/google/cloud/eventarc_v1/__init__.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,28 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.eventarc",
33+
f"{__name__}.types.channel",
34+
f"{__name__}.types.channel_connection",
35+
f"{__name__}.types.discovery",
36+
f"{__name__}.types.enrollment",
37+
f"{__name__}.types.eventarc",
38+
f"{__name__}.types.google_api_source",
39+
f"{__name__}.types.google_channel_config",
40+
f"{__name__}.types.logging_config",
41+
f"{__name__}.types.message_bus",
42+
f"{__name__}.types.network_config",
43+
f"{__name__}.types.pipeline",
44+
f"{__name__}.types.trigger",
45+
}
46+
2547

2648
from .services.eventarc import EventarcClient
2749
from .services.eventarc import EventarcAsyncClient

packages/gapic-generator/tests/integration/goldens/logging/google/cloud/logging_v2/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.config_service_v2",
33+
f"{__name__}.services.logging_service_v2",
34+
f"{__name__}.services.metrics_service_v2",
35+
f"{__name__}.types.log_entry",
36+
f"{__name__}.types.logging",
37+
f"{__name__}.types.logging_config",
38+
f"{__name__}.types.logging_metrics",
39+
}
40+
2541

2642
from .services.config_service_v2 import ConfigServiceV2Client
2743
from .services.config_service_v2 import ConfigServiceV2AsyncClient

packages/gapic-generator/tests/integration/goldens/logging_internal/google/cloud/logging_v2/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.config_service_v2",
33+
f"{__name__}.services.logging_service_v2",
34+
f"{__name__}.services.metrics_service_v2",
35+
f"{__name__}.types.log_entry",
36+
f"{__name__}.types.logging",
37+
f"{__name__}.types.logging_config",
38+
f"{__name__}.types.logging_metrics",
39+
}
40+
2541

2642
from .services.config_service_v2 import BaseConfigServiceV2Client
2743
from .services.config_service_v2 import BaseConfigServiceV2AsyncClient

packages/gapic-generator/tests/integration/goldens/redis/google/cloud/redis_v1/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.cloud_redis",
33+
f"{__name__}.types.cloud_redis",
34+
}
35+
2536

2637
from .services.cloud_redis import CloudRedisClient
2738
from .services.cloud_redis import CloudRedisAsyncClient

packages/gapic-generator/tests/integration/goldens/redis_selective/google/cloud/redis_v1/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.cloud_redis",
33+
f"{__name__}.types.cloud_redis",
34+
}
35+
2536

2637
from .services.cloud_redis import CloudRedisClient
2738
from .services.cloud_redis import CloudRedisAsyncClient

packages/gapic-generator/tests/integration/goldens/storagebatchoperations/google/cloud/storagebatchoperations_v1/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@
2222

2323
from importlib import metadata
2424

25+
# PEP 0810: Explicit Lazy Imports
26+
# Python 3.15+ natively intercepts and defers these imports.
27+
# Developers can disable this behavior and force eager imports.
28+
# For more information, see:
29+
# https://docs.python.org/3.15/library/sys.html#sys.set_lazy_imports_filter
30+
# Older Python versions safely ignore this variable.
31+
__lazy_modules__ = {
32+
f"{__name__}.services.storage_batch_operations",
33+
f"{__name__}.types.storage_batch_operations",
34+
f"{__name__}.types.storage_batch_operations_types",
35+
}
36+
2537

2638
from .services.storage_batch_operations import StorageBatchOperationsClient
2739
from .services.storage_batch_operations import StorageBatchOperationsAsyncClient

0 commit comments

Comments
 (0)