Skip to content

Commit e7ecdbd

Browse files
authored
Improve pyproject.toml synchronization hook with fallback logic (#61597)
Add fallback mechanism for provider minimum version detection when metadata is unavailable. The hook now attempts to read local provider pyproject.toml files as a fallback before giving up. Changes: - Add get_local_provider_version() to read from local pyproject.toml - Extract fallback logic into _fallback_provider_version() helper - Add extra_information parameter to insert_documentation() for clearer update messages showing what was synchronized This ensures the hook works correctly even for providers without published metadata, improving reliability during development.
1 parent 09a15a4 commit e7ecdbd

2 files changed

Lines changed: 75 additions & 11 deletions

File tree

scripts/ci/prek/common_prek_utils.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,12 @@ def pre_process_files(files: list[str]) -> list[str]:
129129

130130

131131
def insert_documentation(
132-
file_path: Path, content: list[str], header: str, footer: str, add_comment: bool = False
132+
file_path: Path,
133+
content: list[str],
134+
header: str,
135+
footer: str,
136+
add_comment: bool = False,
137+
extra_information: str | None = None,
133138
) -> bool:
134139
found = False
135140
old_content = file_path.read_text()
@@ -155,7 +160,7 @@ def insert_documentation(
155160
sys.exit(1)
156161
if new_content != old_content:
157162
file_path.write_text(new_content)
158-
console.print(f"Updated {file_path}")
163+
console.print(f"Updated {file_path} with {extra_information or 'generated documentation'}")
159164
return True
160165
return False
161166

scripts/ci/prek/update_airflow_pyproject_toml.py

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,49 @@ def provider_path(provider_id: str) -> str:
108108
all_providers_dependencies = json.loads(PROVIDER_DEPENDENCIES_FILE_PATH.read_text())
109109

110110

111+
def _read_toml(path: Path) -> dict[str, Any]:
112+
try:
113+
import tomllib
114+
except ImportError:
115+
import tomli as tomllib
116+
return tomllib.loads(path.read_text())
117+
118+
119+
def get_local_provider_version(provider_id: str) -> Version | None:
120+
provider_pyproject = PROVIDERS_DIR / provider_path(provider_id) / "pyproject.toml"
121+
if not provider_pyproject.exists():
122+
return None
123+
try:
124+
provider_toml = _read_toml(provider_pyproject)
125+
except Exception:
126+
return None
127+
version_str = provider_toml.get("project", {}).get("version")
128+
if not version_str:
129+
return None
130+
return parse_version(version_str)
131+
132+
133+
def _fallback_provider_version(
134+
provider_id: str, min_version_override: Version | None
135+
) -> tuple[Version | None, str]:
136+
if min_version_override:
137+
console.print(
138+
f"[yellow]Provider id {provider_id} min version fallback:[/] "
139+
f"MIN_VERSION_OVERRIDE -> {min_version_override}"
140+
)
141+
return min_version_override, f" # Set from MIN_VERSION_OVERRIDE in {Path(__file__).name}"
142+
local_version = get_local_provider_version(provider_id)
143+
if local_version:
144+
console.print(
145+
f"[yellow]Provider id {provider_id} min version fallback:[/] "
146+
f"local provider pyproject.toml -> {local_version}"
147+
)
148+
return local_version, " # Set from local provider pyproject.toml"
149+
return None, ""
150+
151+
111152
def find_min_provider_version(provider_id: str) -> tuple[Version | None, str]:
153+
console.print(f"[bright_blue]Finding min version for provider id:[/] {provider_id}")
112154
metadata = all_providers_metadata.get(provider_id)
113155
# We should periodically update the starting date to avoid pip install resolution issues
114156
# TODO: when min Python version is 3.11 change back the code to fromisoformat
@@ -119,10 +161,11 @@ def find_min_provider_version(provider_id: str) -> tuple[Version | None, str]:
119161
last_version_newer_than_cutoff: Version | None = None
120162
date_released: datetime | None = None
121163
min_version_override = MIN_VERSION_OVERRIDE.get(provider_id)
164+
override_comment = ""
122165
if not metadata:
123-
if not min_version_override:
124-
return None, ""
125-
last_version_newer_than_cutoff = min_version_override
166+
last_version_newer_than_cutoff, override_comment = _fallback_provider_version(
167+
provider_id, min_version_override
168+
)
126169
else:
127170
versions: list[Version] = sorted([parse_version(version) for version in metadata], reverse=True)
128171
for version in versions:
@@ -133,11 +176,19 @@ def find_min_provider_version(provider_id: str) -> tuple[Version | None, str]:
133176
if date_released < cut_off_date:
134177
break
135178
last_version_newer_than_cutoff = version
136-
console.print(
137-
f"[bright_blue]Provider id {provider_id} min version found:[/] "
138-
f"{last_version_newer_than_cutoff} (date {date_released}"
139-
)
140-
override_comment = ""
179+
if not last_version_newer_than_cutoff:
180+
last_version_newer_than_cutoff, override_comment = _fallback_provider_version(
181+
provider_id, min_version_override
182+
)
183+
if date_released:
184+
console.print(
185+
f"[bright_blue]Provider id {provider_id} min version found:[/] "
186+
f"{last_version_newer_than_cutoff} (date {date_released})"
187+
)
188+
else:
189+
console.print(
190+
f"[yellow]Provider id {provider_id} has no released versions newer than cutoff date {cut_off_date}![/]"
191+
)
141192
if last_version_newer_than_cutoff:
142193
if min_version_override and min_version_override > last_version_newer_than_cutoff:
143194
console.print(
@@ -216,13 +267,17 @@ def get_python_exclusion(provider_dependencies: dict[str, Any]) -> str:
216267
all_optional_dependencies,
217268
START_OPTIONAL_DEPENDENCIES,
218269
END_OPTIONAL_DEPENDENCIES,
270+
False,
271+
"optional dependencies",
219272
)
220273
all_mypy_paths = []
221274
for provider_id in all_providers:
222275
provider_mypy_path = f"$MYPY_CONFIG_FILE_DIR/providers/{provider_path(provider_id)}"
223276
all_mypy_paths.append(f' "{provider_mypy_path}/src",\n')
224277
all_mypy_paths.append(f' "{provider_mypy_path}/tests",\n')
225-
insert_documentation(AIRFLOW_PYPROJECT_TOML_FILE, all_mypy_paths, START_MYPY_PATHS, END_MYPY_PATHS)
278+
insert_documentation(
279+
AIRFLOW_PYPROJECT_TOML_FILE, all_mypy_paths, START_MYPY_PATHS, END_MYPY_PATHS, False, "mypy paths"
280+
)
226281
all_workspace_items = []
227282
for provider_id in all_providers:
228283
all_workspace_items.append(f"{provider_distribution_name(provider_id)} = {{ workspace = true }}\n")
@@ -231,6 +286,8 @@ def get_python_exclusion(provider_dependencies: dict[str, Any]) -> str:
231286
all_workspace_items,
232287
START_WORKSPACE_ITEMS,
233288
END_WORKSPACE_ITEMS,
289+
False,
290+
"workspace items",
234291
)
235292
all_workspace_members = []
236293
for provider_id in all_providers:
@@ -240,4 +297,6 @@ def get_python_exclusion(provider_dependencies: dict[str, Any]) -> str:
240297
all_workspace_members,
241298
START_PROVIDER_WORKSPACE_MEMBERS,
242299
END_PROVIDER_WORKSPACE_MEMBERS,
300+
False,
301+
"provider workspace members",
243302
)

0 commit comments

Comments
 (0)