This is an automated email from the ASF dual-hosted git repository.
kaxil pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new fca1c01c73e Fix Windows UnicodeDecodeError during pytest collection
(#73536)
fca1c01c73e is described below
commit fca1c01c73ee41690d3a209e8d45335868e1fe53
Author: Divyansh Yadav <[email protected]>
AuthorDate: Fri Oct 2 04:28:04 2026 +0530
Fix Windows UnicodeDecodeError during pytest collection (#73536)
---
devel-common/src/tests_common/pytest_plugin.py | 9 +++++---
.../src/tests_common/test_utils/providers.py | 2 +-
scripts/ci/prek/common_prek_utils.py | 26 ++++++++++++----------
scripts/ci/prek/update_providers_dependencies.py | 14 ++++++------
4 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/devel-common/src/tests_common/pytest_plugin.py
b/devel-common/src/tests_common/pytest_plugin.py
index bb85fe60c2d..63abaaaba18 100644
--- a/devel-common/src/tests_common/pytest_plugin.py
+++ b/devel-common/src/tests_common/pytest_plugin.py
@@ -166,7 +166,7 @@ ALL_PYPROJECT_TOML_FILES: list[Path] = []
def get_all_provider_pyproject_toml_provider_yaml_files() -> Generator[Path,
None, None]:
- pyproject_toml_content =
AIRFLOW_PYPROJECT_TOML_FILE_PATH.read_text().splitlines()
+ pyproject_toml_content =
AIRFLOW_PYPROJECT_TOML_FILE_PATH.read_text(encoding="utf-8").splitlines()
in_workspace = False
for line in pyproject_toml_content:
trimmed_line = line.strip()
@@ -198,9 +198,12 @@ if not PROVIDER_DEPENDENCIES_JSON_PATH.exists() or not
PROVIDER_DEPENDENCIES_JSO
subprocess.check_call(["uv", "run",
UPDATE_PROVIDER_DEPENDENCIES_SCRIPT.as_posix()])
else:
calculated_provider_deps_hash = _calculate_provider_deps_hash()
- if calculated_provider_deps_hash.strip() !=
PROVIDER_DEPENDENCIES_JSON_HASH_PATH.read_text().strip():
+ if (
+ calculated_provider_deps_hash.strip()
+ !=
PROVIDER_DEPENDENCIES_JSON_HASH_PATH.read_text(encoding="utf-8").strip()
+ ):
subprocess.check_call(["uv", "run",
UPDATE_PROVIDER_DEPENDENCIES_SCRIPT.as_posix()])
-
PROVIDER_DEPENDENCIES_JSON_HASH_PATH.write_text(calculated_provider_deps_hash)
+
PROVIDER_DEPENDENCIES_JSON_HASH_PATH.write_text(calculated_provider_deps_hash,
encoding="utf-8")
# End of copied code from breeze
os.environ["AIRFLOW__CORE__ALLOWED_DESERIALIZATION_CLASSES"] =
"airflow.*\nunit.*\n"
diff --git a/devel-common/src/tests_common/test_utils/providers.py
b/devel-common/src/tests_common/test_utils/providers.py
index 37a999f3422..fc3778e6c01 100644
--- a/devel-common/src/tests_common/test_utils/providers.py
+++ b/devel-common/src/tests_common/test_utils/providers.py
@@ -78,7 +78,7 @@ def get_suspended_providers_folders() -> list[str]:
"""
suspended_providers = []
for provider_path in AIRFLOW_PROVIDERS_ROOT_PATH.rglob("provider.yaml"):
- provider_yaml = yaml.safe_load(provider_path.read_text())
+ provider_yaml =
yaml.safe_load(provider_path.read_text(encoding="utf-8"))
if provider_yaml["state"] == "suspended":
suspended_providers.append(provider_path.parent.resolve().as_posix())
return suspended_providers
diff --git a/scripts/ci/prek/common_prek_utils.py
b/scripts/ci/prek/common_prek_utils.py
index 3a799b2dd19..b68ec286611 100644
--- a/scripts/ci/prek/common_prek_utils.py
+++ b/scripts/ci/prek/common_prek_utils.py
@@ -121,7 +121,7 @@ def run_command(*args, **kwargs) -> None:
def read_airflow_version() -> str:
- ast_obj = ast.parse((AIRFLOW_CORE_SOURCES_PATH / "airflow" /
"__init__.py").read_text())
+ ast_obj = ast.parse((AIRFLOW_CORE_SOURCES_PATH / "airflow" /
"__init__.py").read_text(encoding="utf-8"))
for node in ast_obj.body:
if isinstance(node, ast.Assign):
if node.targets[0].id == "__version__": # type:
ignore[attr-defined]
@@ -142,7 +142,7 @@ def _read_global_constants_assignment(name: str) -> Any:
(``NAME: type = ...``). The value must be a literal so it can be safely
evaluated with ``ast.literal_eval``.
"""
- tree = ast.parse(GLOBAL_CONSTANTS_PATH.read_text())
+ tree = ast.parse(GLOBAL_CONSTANTS_PATH.read_text(encoding="utf-8"))
for node in tree.body:
if isinstance(node, ast.Assign):
for target in node.targets:
@@ -229,7 +229,7 @@ def insert_documentation(
extra_information: str | None = None,
) -> bool:
found = False
- old_content = file_path.read_text()
+ old_content = file_path.read_text(encoding="utf-8")
lines = old_content.splitlines(keepends=True)
replacing = False
result: list[str] = []
@@ -251,7 +251,7 @@ def insert_documentation(
print(f"Header {header} not found in {file_path}")
sys.exit(1)
if new_content != old_content:
- file_path.write_text(new_content)
+ file_path.write_text(new_content, encoding="utf-8")
console.print(f"Updated {file_path} with {extra_information or
'generated documentation'}")
return True
return False
@@ -277,7 +277,7 @@ def read_uv_required_min_version() -> tuple[str, tuple[int,
...]]:
Parses ``[tool.uv] required-version = ">=X.Y.Z"`` and returns ``(raw,
tuple)``.
We parse by regex to avoid pulling a TOML dep into every prek script.
"""
- pyproject = (AIRFLOW_ROOT_PATH / "pyproject.toml").read_text()
+ pyproject = (AIRFLOW_ROOT_PATH /
"pyproject.toml").read_text(encoding="utf-8")
# Narrow to the [tool.uv] section so we don't match a different
required-version.
match = re.search(r"^\[tool\.uv\]\s*$(?P<body>.*?)(?=^\[|\Z)", pyproject,
re.MULTILINE | re.DOTALL)
if not match:
@@ -381,12 +381,14 @@ def describe_breeze_not_running_from_lock() -> str | None:
if resolved.is_relative_to(BREEZE_LOCKED_VENV_PATH.resolve()):
return None
try:
- text = Path(breeze_bin).read_text()
+ text = Path(breeze_bin).read_text(encoding="utf-8")
except (OSError, UnicodeDecodeError):
return None
if BREEZE_SHIM_MARKER not in text:
return f"`{breeze_bin}` is a legacy global install, which ignores the
lock"
- expected_version = _read_shim_version(SETUP_BREEZE_PATH.read_text(),
SETUP_BREEZE_SHIM_VERSION_PREFIX)
+ expected_version = _read_shim_version(
+ SETUP_BREEZE_PATH.read_text(encoding="utf-8"),
SETUP_BREEZE_SHIM_VERSION_PREFIX
+ )
if expected_version is None:
return None
installed_version = _read_shim_version(text, BREEZE_SHIM_VERSION_PREFIX)
@@ -693,7 +695,7 @@ def get_all_provider_ids(
if excluded_states:
import yaml
- provider_info = yaml.safe_load(provider_file.read_text())
+ provider_info =
yaml.safe_load(provider_file.read_text(encoding="utf-8"))
if provider_info.get("state") in excluded_states:
continue
provider_id = get_provider_id_from_path(provider_file)
@@ -723,7 +725,7 @@ def get_all_provider_info_dicts() -> dict[str, dict]:
provider_id =
str(provider_file.parent.relative_to(AIRFLOW_PROVIDERS_ROOT_PATH)).replace(os.sep,
".")
import yaml
- provider_info = yaml.safe_load(provider_file.read_text())
+ provider_info =
yaml.safe_load(provider_file.read_text(encoding="utf-8"))
if provider_info["state"] != "suspended":
providers[provider_id] = provider_info
return providers
@@ -880,7 +882,7 @@ def get_imports_from_file(file_path: Path, *,
only_top_level: bool) -> list[str]
When only_top_level = False then returns
['os', 'collections.defaultdict', 'numpy', 'pandas.DataFrame', 'json',
'pathlib.Path', 'pathlib.PurePath']
"""
- root = ast.parse(file_path.read_text(), file_path.name)
+ root = ast.parse(file_path.read_text(encoding="utf-8"), file_path.name)
imports: list[str] = []
nodes = ast.iter_child_nodes(root) if only_top_level else ast.walk(root)
@@ -1070,11 +1072,11 @@ class AllowlistManager(abc.ABC):
"""Return mapping of ``relative_path -> allowed_count``."""
if not self.allowlist_file.exists():
return {}
- return self.parse(self.allowlist_file.read_text())
+ return self.parse(self.allowlist_file.read_text(encoding="utf-8"))
def save(self, counts: dict[str, int]) -> None:
lines = [f"{rel}::{count}" for rel, count in sorted(counts.items())]
- self.allowlist_file.write_text("\n".join(lines) + "\n")
+ self.allowlist_file.write_text("\n".join(lines) + "\n",
encoding="utf-8")
@abc.abstractmethod
def iter_files(self) -> Iterable[Path]:
diff --git a/scripts/ci/prek/update_providers_dependencies.py
b/scripts/ci/prek/update_providers_dependencies.py
index 41b0c4fe79f..ce0a4651a0d 100755
--- a/scripts/ci/prek/update_providers_dependencies.py
+++ b/scripts/ci/prek/update_providers_dependencies.py
@@ -70,7 +70,7 @@ def load_pyproject_toml(pyproject_toml_file_path: Path) ->
dict[str, Any]:
import tomllib
except ImportError:
import tomli as tomllib # type: ignore[no-redef]
- return tomllib.loads(pyproject_toml_file_path.read_text())
+ return tomllib.loads(pyproject_toml_file_path.read_text(encoding="utf-8"))
def find_all_providers_and_provider_files():
@@ -95,7 +95,7 @@ def find_all_providers_and_provider_files():
f"The provider {provider_name} does not have 'src'
folder"
f" in {provider_yaml_file.parent}"
)
- provider_info = yaml.safe_load(provider_yaml_file.read_text())
+ provider_info =
yaml.safe_load(provider_yaml_file.read_text(encoding="utf-8"))
if provider_info["state"] == "suspended":
suspended_paths.append(
provider_yaml_file.parent.relative_to(AIRFLOW_PROVIDERS_ROOT_PATH).as_posix()
@@ -226,13 +226,13 @@ if __name__ == "__main__":
console.print("[red]Errors found during verification. Exiting!")
console.print()
sys.exit(1)
- old_dependencies = (
- DEPENDENCIES_JSON_FILE_PATH.read_text() if
DEPENDENCIES_JSON_FILE_PATH.exists() else "{}"
+ old_content = (
+ DEPENDENCIES_JSON_FILE_PATH.read_text(encoding="utf-8")
+ if DEPENDENCIES_JSON_FILE_PATH.exists()
+ else ""
)
- new_dependencies = json.dumps(unique_sorted_dependencies, indent=2) + "\n"
- old_content = DEPENDENCIES_JSON_FILE_PATH.read_text() if
DEPENDENCIES_JSON_FILE_PATH.exists() else ""
new_content = json.dumps(unique_sorted_dependencies, indent=2) + "\n"
- DEPENDENCIES_JSON_FILE_PATH.write_text(new_content)
+ DEPENDENCIES_JSON_FILE_PATH.write_text(new_content, encoding="utf-8")
if new_content != old_content:
console.print()
console.print(f"Written {DEPENDENCIES_JSON_FILE_PATH}")