diff --git a/.gitignore b/.gitignore index 7b322be51..1cdf9fe3a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ !/create_types_pyi.py !/stubdefaulter.sh !/stubgen.py +!/fixup_versions.py __pycache__ diff --git a/fixup_versions.py b/fixup_versions.py new file mode 100644 index 000000000..ccc235392 --- /dev/null +++ b/fixup_versions.py @@ -0,0 +1,157 @@ +import re + +from google.ads.googleads import client + +sorted_versions = sorted(client._VALID_API_VERSIONS) + + +def replace_between_markers(content, marker_prefix, marker_suffix, replacement): + replacement = "\n".join([marker_prefix, replacement, marker_suffix]) + new_content = re.sub( + f"{marker_prefix}.+{marker_suffix}", + replacement, + content, + flags=re.DOTALL, + ) + return new_content + + +def fix_interceptors(): + interceptor_imports = [] + interceptor_request_types = [] + + for version in sorted_versions: + interceptor_imports.append(f"import google.ads.googleads.{version}.services") + interceptor_request_types.append( + f"google.ads.googleads.{version}.services.SearchGoogleAdsRequest" + ) + interceptor_request_types.append( + f"google.ads.googleads.{version}.services.SearchGoogleAdsStreamRequest" + ) + + interceptor_imports_prefix = "# Autogenerated imports" + interceptor_imports_suffix = "# End of autogenerated imports" + interceptor_request_types_prefix = "# Autogenerated request types" + interceptor_request_types_suffix = "# End of autogenerated request types" + + interceptor_import_replacement = "\n".join(interceptor_imports) + interceptor_request_types_replacement = ",\n".join(interceptor_request_types) + + interceptor_files = [ + "google-stubs/ads/googleads/interceptors/exception_interceptor.pyi", + "google-stubs/ads/googleads/interceptors/logging_interceptor.pyi", + "google-stubs/ads/googleads/interceptors/metadata_interceptor.pyi", + ] + + for interceptor_file in interceptor_files: + with open(interceptor_file) as f: + interceptor_pyi = f.read() + interceptor_pyi = replace_between_markers( + interceptor_pyi, + interceptor_imports_prefix, + interceptor_imports_suffix, + interceptor_import_replacement, + ) + interceptor_pyi = replace_between_markers( + interceptor_pyi, + interceptor_request_types_prefix, + interceptor_request_types_suffix, + interceptor_request_types_replacement, + ) + with open(interceptor_file, mode="w") as f: + f.write(interceptor_pyi) + + +def fix_errors(): + error_imports = [] + error_types = [] + + for version in sorted_versions: + error_imports.append( + f"from google.ads.googleads.{version}.errors import GoogleAdsFailure as GoogleAdsFailure{version.upper()}" + ) + error_types.append(f"GoogleAdsFailure{version.upper()}") + + error_imports_prefix = "# Autogenerated imports" + error_imports_suffix = "# End of autogenerated imports" + error_types_prefix = "# Autogenerated failure types" + error_types_suffix = "# End of autogenerated failure types" + + error_imports_replacement = "\n".join(error_imports) + error_types_replacement = " | ".join(error_types) + + with open("google-stubs/ads/googleads/errors.pyi") as f: + errors_pyi = f.read() + + errors_pyi = replace_between_markers( + errors_pyi, + error_imports_prefix, + error_imports_suffix, + error_imports_replacement, + ) + errors_pyi = replace_between_markers( + errors_pyi, + error_types_prefix, + error_types_suffix, + error_types_replacement, + ) + with open("google-stubs/ads/googleads/errors.pyi", mode="w") as f: + f.write(errors_pyi) + + +def fix_client(): + default_version_import = ( + f"from google.ads.googleads import {client._DEFAULT_VERSION}" + ) + + default_version_import_prefix = "# Autogenerated import of latest version" + default_version_import_suffix = "# End of autogenerated import of latest version" + + with open("google-stubs/ads/googleads/client.pyi") as f: + client_pyi = f.read() + + client_pyi = replace_between_markers( + client_pyi, + default_version_import_prefix, + default_version_import_suffix, + default_version_import, + ) + + version_literals = [] + for version in sorted_versions: + version_literals.append(f'_{version.upper()} = Literal["{version}"]') + version_literals.append( + f"_V = {' | '.join([f'_{version.upper()}' for version in sorted_versions])}" + ) + + version_literals_prefix = "# Autogenerated version literals" + version_literals_suffix = "# End of autogenerated version literals" + + version_literals_replacement = "\n".join(version_literals) + + client_pyi = replace_between_markers( + client_pyi, + version_literals_prefix, + version_literals_suffix, + version_literals_replacement, + ) + + get_type_overload = f' def get_type(cls, name: str, version: _V = "{client._DEFAULT_VERSION}") -> Any: ...' + + get_type_overload_prefix = " # Autogenerated get_type overload" + get_type_overload_suffix = " # End of autogenerated get_type overload" + + client_pyi = replace_between_markers( + client_pyi, + get_type_overload_prefix, + get_type_overload_suffix, + get_type_overload, + ) + + with open("google-stubs/ads/googleads/client.pyi", mode="w") as f: + f.write(client_pyi) + + +fix_interceptors() +fix_errors() +fix_client() diff --git a/gen.sh b/gen.sh index ff38820ba..40f7c45aa 100644 --- a/gen.sh +++ b/gen.sh @@ -3,12 +3,8 @@ set -eou pipefail shopt -s globstar -# Manual: Clone https://github.com/googleads/google-ads-python -# Manual: Update google-ads-python dependency -# Manual: Update the following to match the API versions: -# - GoogleAdsFailure in errors.pyi -# - _V, imports and get_type default in client.pyi -# - _Request in exception_interceptor.pyi, logging_interceptor.pyi and metadata_interceptor.pyi +uv remove google-ads && uv add google-ads +git clone https://github.com/googleads/google-ads-python.git || true cd google-ads-python git restore . git pull @@ -21,8 +17,9 @@ uv run python stubgen.py uv run python create_type_stubs.py uv run python create_enums.py uv run python create_service_overloads.py +uv run python fixup_versions.py ./stubdefaulter.sh -mv .gitignore gitignore +mv .gitignore gitignore # Workaround for ruff's handling of gitignore files with whitelisting. uv run ruff check google-stubs --fix --unsafe-fixes uv run ruff format google-stubs mv gitignore .gitignore diff --git a/google-stubs/ads/googleads/client.pyi b/google-stubs/ads/googleads/client.pyi index 6d14392cf..7d59d6c34 100644 --- a/google-stubs/ads/googleads/client.pyi +++ b/google-stubs/ads/googleads/client.pyi @@ -437,14 +437,19 @@ import google.ads.googleads.v23.services.services.user_list_customer_type_servic import google.ads.googleads.v23.services.services.user_list_service # End of autogenerated service imports +# Autogenerated import of latest version from google.ads.googleads import v23 + +# End of autogenerated import of latest version from google.ads.googleads.config import _ConfigDataUnparsed +# Autogenerated version literals _V20 = Literal["v20"] _V21 = Literal["v21"] _V22 = Literal["v22"] _V23 = Literal["v23"] _V = _V20 | _V21 | _V22 | _V23 +# End of autogenerated version literals class _EnumGetter: # Autogenerated enums @@ -1303,7 +1308,9 @@ class GoogleAdsClient: use_proto_plus: bool = False, use_cloud_org_for_api_access: bool | None = None, ) -> None: ... + # Autogenerated get_type overload def get_type(cls, name: str, version: _V = "v23") -> Any: ... + # End of autogenerated get_type overload # Autogenerated service overloads @overload def get_service( diff --git a/google-stubs/ads/googleads/errors.pyi b/google-stubs/ads/googleads/errors.pyi index 22945ad78..0a3aac6fb 100644 --- a/google-stubs/ads/googleads/errors.pyi +++ b/google-stubs/ads/googleads/errors.pyi @@ -1,15 +1,20 @@ import grpc +# Autogenerated imports from google.ads.googleads.v20.errors import GoogleAdsFailure as GoogleAdsFailureV20 from google.ads.googleads.v21.errors import GoogleAdsFailure as GoogleAdsFailureV21 from google.ads.googleads.v22.errors import GoogleAdsFailure as GoogleAdsFailureV22 from google.ads.googleads.v23.errors import GoogleAdsFailure as GoogleAdsFailureV23 +# End of autogenerated imports + GoogleAdsFailure = ( + # Autogenerated failure types GoogleAdsFailureV20 | GoogleAdsFailureV21 | GoogleAdsFailureV22 | GoogleAdsFailureV23 + # End of autogenerated failure types ) class GoogleAdsException(Exception): diff --git a/google-stubs/ads/googleads/interceptors/exception_interceptor.pyi b/google-stubs/ads/googleads/interceptors/exception_interceptor.pyi index 759fa4504..76c73d78b 100644 --- a/google-stubs/ads/googleads/interceptors/exception_interceptor.pyi +++ b/google-stubs/ads/googleads/interceptors/exception_interceptor.pyi @@ -3,15 +3,18 @@ from typing import TypeVar import grpc +# Autogenerated imports import google.ads.googleads.v20.services import google.ads.googleads.v21.services import google.ads.googleads.v22.services import google.ads.googleads.v23.services +# End of autogenerated imports from .interceptor import Interceptor _Request = TypeVar( "_Request", + # Autogenerated request types google.ads.googleads.v20.services.SearchGoogleAdsRequest, google.ads.googleads.v20.services.SearchGoogleAdsStreamRequest, google.ads.googleads.v21.services.SearchGoogleAdsRequest, @@ -20,6 +23,7 @@ _Request = TypeVar( google.ads.googleads.v22.services.SearchGoogleAdsStreamRequest, google.ads.googleads.v23.services.SearchGoogleAdsRequest, google.ads.googleads.v23.services.SearchGoogleAdsStreamRequest, + # End of autogenerated request types ) _Response = TypeVar("_Response") diff --git a/google-stubs/ads/googleads/interceptors/logging_interceptor.pyi b/google-stubs/ads/googleads/interceptors/logging_interceptor.pyi index 6a78d1af3..362c76330 100644 --- a/google-stubs/ads/googleads/interceptors/logging_interceptor.pyi +++ b/google-stubs/ads/googleads/interceptors/logging_interceptor.pyi @@ -5,15 +5,18 @@ from typing import TypeVar import grpc from google.protobuf.message import Message +# Autogenerated imports import google.ads.googleads.v20.services import google.ads.googleads.v21.services import google.ads.googleads.v22.services import google.ads.googleads.v23.services +# End of autogenerated imports from .interceptor import Interceptor _Request = TypeVar( "_Request", + # Autogenerated request types google.ads.googleads.v20.services.SearchGoogleAdsRequest, google.ads.googleads.v20.services.SearchGoogleAdsStreamRequest, google.ads.googleads.v21.services.SearchGoogleAdsRequest, @@ -22,6 +25,7 @@ _Request = TypeVar( google.ads.googleads.v22.services.SearchGoogleAdsStreamRequest, google.ads.googleads.v23.services.SearchGoogleAdsRequest, google.ads.googleads.v23.services.SearchGoogleAdsStreamRequest, + # End of autogenerated request types ) _Response = TypeVar("_Response") diff --git a/google-stubs/ads/googleads/interceptors/metadata_interceptor.pyi b/google-stubs/ads/googleads/interceptors/metadata_interceptor.pyi index e292fca14..cec1a904a 100644 --- a/google-stubs/ads/googleads/interceptors/metadata_interceptor.pyi +++ b/google-stubs/ads/googleads/interceptors/metadata_interceptor.pyi @@ -3,15 +3,18 @@ from typing import TypeVar import grpc +# Autogenerated imports import google.ads.googleads.v20.services import google.ads.googleads.v21.services import google.ads.googleads.v22.services import google.ads.googleads.v23.services +# End of autogenerated imports from .interceptor import Interceptor _Request = TypeVar( "_Request", + # Autogenerated request types google.ads.googleads.v20.services.SearchGoogleAdsRequest, google.ads.googleads.v20.services.SearchGoogleAdsStreamRequest, google.ads.googleads.v21.services.SearchGoogleAdsRequest, @@ -20,6 +23,7 @@ _Request = TypeVar( google.ads.googleads.v22.services.SearchGoogleAdsStreamRequest, google.ads.googleads.v23.services.SearchGoogleAdsRequest, google.ads.googleads.v23.services.SearchGoogleAdsStreamRequest, + # End of autogenerated request types ) _Response = TypeVar("_Response")