From b44f8cb6645700835e0d5d6838c42443c1d9c389 Mon Sep 17 00:00:00 2001 From: Pankaj Singh Date: Thu, 14 May 2026 21:13:24 +0530 Subject: [PATCH 1/2] Convert remaining f-string logger calls to lazy form Follow-up to #2672. The original sweep caught ~47 single-line logger.X(f"...") sites but missed two patterns: 1. Multi-line calls of the form logger.exception( f"..." ) in cosmos/plugin/airflow3.py (three sites) and cosmos/dbt/parser/output.py (one site). The original regex required the f-string on the same line as the logger call. 2. self.log.X(f"...") calls in operators that inherit Airflow's LoggingMixin. These never matched the original logger.X(f"...") pattern even though they violate the lazy logging rule identically. Affects azure_container_instance, docker, kubernetes, aws_ecs, gcp_cloud_run_job, and virtualenv operators. Also converts one eager percent-interpolation call in cosmos/cache.py ("%s" % repr(e)) that used %-formatting instead of an f-string and so was outside the scope of #2672. No behaviour change. Co-Authored-By: Claude Opus 4.7 (1M context) --- cosmos/cache.py | 2 +- cosmos/dbt/parser/output.py | 3 ++- cosmos/operators/aws_ecs.py | 2 +- cosmos/operators/azure_container_instance.py | 2 +- cosmos/operators/docker.py | 2 +- cosmos/operators/gcp_cloud_run_job.py | 2 +- cosmos/operators/kubernetes.py | 2 +- cosmos/operators/virtualenv.py | 14 +++++++------- cosmos/plugin/airflow3.py | 17 ++++++++++++++--- 9 files changed, 29 insertions(+), 17 deletions(-) diff --git a/cosmos/cache.py b/cosmos/cache.py index 2d3cb43c96..8feb958b3a 100644 --- a/cosmos/cache.py +++ b/cosmos/cache.py @@ -236,7 +236,7 @@ def patch_partial_parse_content(partial_parse_filepath: Path, project_path: Path # it may be due a race condition of multiple processes trying to read/write this file data = msgpack.unpack(f) except ValueError as e: - logger.info("Unable to patch the partial_parse.msgpack file due to %s" % repr(e)) + logger.info("Unable to patch the partial_parse.msgpack file due to %r", e) else: for node in data["nodes"].values(): expected_filepath = node.get("root_path") diff --git a/cosmos/dbt/parser/output.py b/cosmos/dbt/parser/output.py index 8512c79aef..03f8b2d31a 100644 --- a/cosmos/dbt/parser/output.py +++ b/cosmos/dbt/parser/output.py @@ -40,7 +40,8 @@ def parse_number_of_warnings_subprocess(result: FullOutputSubprocessResult) -> i num = int(output.split(f"{DBT_WARN_MSG}=")[1].split()[0]) except ValueError: logger.error( - f"Could not parse number of {DBT_WARN_MSG}s. Check your dbt/airflow version or if --quiet is not being used" + "Could not parse number of %ss. Check your dbt/airflow version or if --quiet is not being used", + DBT_WARN_MSG, ) return num diff --git a/cosmos/operators/aws_ecs.py b/cosmos/operators/aws_ecs.py index 4dfafef5b7..55b5349b4f 100644 --- a/cosmos/operators/aws_ecs.py +++ b/cosmos/operators/aws_ecs.py @@ -125,7 +125,7 @@ def build_and_run_cmd( ) -> Any: self.invoke_interceptors(context) self.build_command(context, cmd_flags) - self.log.info(f"Running command: {self.command}") + self.log.info("Running command: %s", self.command) result = EcsRunTaskOperator.execute(self, context) diff --git a/cosmos/operators/azure_container_instance.py b/cosmos/operators/azure_container_instance.py index 614e1f224d..13791975cf 100644 --- a/cosmos/operators/azure_container_instance.py +++ b/cosmos/operators/azure_container_instance.py @@ -115,7 +115,7 @@ def build_and_run_cmd( ) -> Any: self.invoke_interceptors(context) self.build_command(context, cmd_flags) - self.log.info(f"Running command: {self.command}") + self.log.info("Running command: %s", self.command) result = AzureContainerInstancesOperator.execute(self, context) self.log.info(result) diff --git a/cosmos/operators/docker.py b/cosmos/operators/docker.py index 1c16aeb3b1..47549328df 100644 --- a/cosmos/operators/docker.py +++ b/cosmos/operators/docker.py @@ -106,7 +106,7 @@ def build_and_run_cmd( ) -> Any: self.invoke_interceptors(context) self.build_command(context, cmd_flags) - self.log.info(f"Running command: {self.command}") + self.log.info("Running command: %s", self.command) result = DockerOperator.execute(self, context) self.log.info(result) diff --git a/cosmos/operators/gcp_cloud_run_job.py b/cosmos/operators/gcp_cloud_run_job.py index a1c60bbce9..0959e2c63b 100644 --- a/cosmos/operators/gcp_cloud_run_job.py +++ b/cosmos/operators/gcp_cloud_run_job.py @@ -127,7 +127,7 @@ def build_and_run_cmd( ) -> Any: self.invoke_interceptors(context) self.build_command(context, cmd_flags) - self.log.info(f"Running command: {self.command}") + self.log.info("Running command: %s", self.command) result = CloudRunExecuteJobOperator.execute(self, context) logger.info(result) diff --git a/cosmos/operators/kubernetes.py b/cosmos/operators/kubernetes.py index c8a043c8cb..3fd2a9d717 100644 --- a/cosmos/operators/kubernetes.py +++ b/cosmos/operators/kubernetes.py @@ -134,7 +134,7 @@ def build_and_run_cmd( ) -> Any: self.invoke_interceptors(context) self.build_kube_args(context, cmd_flags) - self.log.info(f"Running command: {self.arguments}") + self.log.info("Running command: %s", self.arguments) result = KubernetesPodOperator.execute(self, context) self.log.info(result) diff --git a/cosmos/operators/virtualenv.py b/cosmos/operators/virtualenv.py index 6198d3cde5..823592492f 100644 --- a/cosmos/operators/virtualenv.py +++ b/cosmos/operators/virtualenv.py @@ -99,7 +99,7 @@ def run_subprocess( self, command: list[str], env: dict[str, str], cwd: str, **kwargs: Any ) -> FullOutputSubprocessResult: if self._py_bin is not None: - self.log.info(f"Using Python binary from virtualenv: {self._py_bin}") + self.log.info("Using Python binary from virtualenv: %s", self._py_bin) command[0] = str(Path(self._py_bin).parent / "dbt") return super().run_subprocess(command, env, cwd, **kwargs) @@ -128,7 +128,7 @@ def run_command( ) try: - self.log.info(f"Checking if the virtualenv lock {str(self._lock_file)} exists") + self.log.info("Checking if the virtualenv lock %s exists", self._lock_file) while not self._is_lock_available() and self.max_retries_lock: logger.info("Waiting for virtualenv lock to be released") time.sleep(1) @@ -154,7 +154,7 @@ def clean_dir_if_temporary(self) -> None: Delete the virtualenv directory if it is temporary. """ if self.is_virtualenv_dir_temporary and self.virtualenv_dir and self.virtualenv_dir.exists(): - self.log.info(f"Deleting the Python virtualenv {self.virtualenv_dir}") + self.log.info("Deleting the Python virtualenv %s", self.virtualenv_dir) shutil.rmtree(str(self.virtualenv_dir), ignore_errors=True) def execute(self, context: Context, **kwargs: Any) -> None: @@ -168,7 +168,7 @@ def on_kill(self) -> None: self.clean_dir_if_temporary() def _prepare_virtualenv(self) -> Any: - self.log.info(f"Creating or updating the virtualenv at `{self.virtualenv_dir}") + self.log.info("Creating or updating the virtualenv at `%s", self.virtualenv_dir) py_bin = prepare_virtualenv( venv_directory=str(self.virtualenv_dir), python_bin=PY_INTERPRETER, @@ -193,12 +193,12 @@ def _is_lock_available(self) -> bool: if self._lock_file.is_file(): with open(self._lock_file) as lf: pid = int(lf.read()) - self.log.info(f"Checking for running process with PID {pid}") + self.log.info("Checking for running process with PID %s", pid) try: _process_running = psutil.Process(pid).is_running() - self.log.info(f"Process {pid} running: {_process_running} and has the lock {self._lock_file}.") + self.log.info("Process %s running: %s and has the lock %s.", pid, _process_running, self._lock_file) except psutil.NoSuchProcess: - self.log.info(f"Process {pid} is not running. Lock {self._lock_file} was outdated.") + self.log.info("Process %s is not running. Lock %s was outdated.", pid, self._lock_file) is_available = True else: is_available = not _process_running diff --git a/cosmos/plugin/airflow3.py b/cosmos/plugin/airflow3.py index 9678b1d6b0..909da3bba8 100644 --- a/cosmos/plugin/airflow3.py +++ b/cosmos/plugin/airflow3.py @@ -196,7 +196,10 @@ def dbt_docs_index(slug_alias: str = slug) -> Response: # type: ignore[no-redef ) except (OSError, ValueError, RuntimeError, TimeoutError, PermissionError): logger.exception( - f"Cosmos dbt docs error: index read failed for slug={slug_alias}, path={op.join(docs_dir_local, index_local)}, conn_id={conn_id_local}" + "Cosmos dbt docs error: index read failed for slug=%s, path=%s, conn_id=%s", + slug_alias, + op.join(docs_dir_local, index_local), + conn_id_local, ) return HTMLResponse( content=( @@ -229,7 +232,11 @@ def manifest(slug_alias: str = slug) -> Response: # type: ignore[no-redef] ) except (OSError, ValueError, RuntimeError, TimeoutError, PermissionError) as e: logger.exception( - f"Error reading manifest for slug '{slug_alias}', path '{op.join(docs_dir_local, 'manifest.json')}', conn_id '{conn_id_local}': {e}" + "Error reading manifest for slug '%s', path '%s', conn_id '%s': %s", + slug_alias, + op.join(docs_dir_local, "manifest.json"), + conn_id_local, + e, ) return JSONResponse( content={ @@ -263,7 +270,11 @@ def catalog(slug_alias: str = slug) -> Response: # type: ignore[no-redef] ) except (OSError, ValueError, RuntimeError, TimeoutError, PermissionError) as e: logger.exception( - f"Error reading catalog for slug '{slug_alias}', path '{op.join(docs_dir_local, 'catalog.json')}', conn_id '{conn_id_local}': {e}" + "Error reading catalog for slug '%s', path '%s', conn_id '%s': %s", + slug_alias, + op.join(docs_dir_local, "catalog.json"), + conn_id_local, + e, ) return JSONResponse( content={ From f0464b52ac0671ca2e59bc560e0eed2c7fcc8f86 Mon Sep 17 00:00:00 2001 From: Pankaj Singh <98807258+pankajastro@users.noreply.github.com> Date: Thu, 14 May 2026 21:25:19 +0530 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cosmos/operators/virtualenv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cosmos/operators/virtualenv.py b/cosmos/operators/virtualenv.py index 823592492f..e34b187ef1 100644 --- a/cosmos/operators/virtualenv.py +++ b/cosmos/operators/virtualenv.py @@ -168,7 +168,7 @@ def on_kill(self) -> None: self.clean_dir_if_temporary() def _prepare_virtualenv(self) -> Any: - self.log.info("Creating or updating the virtualenv at `%s", self.virtualenv_dir) + self.log.info("Creating or updating the virtualenv at `%s`", self.virtualenv_dir) py_bin = prepare_virtualenv( venv_directory=str(self.virtualenv_dir), python_bin=PY_INTERPRETER,