Skip to content

Commit 95dec56

Browse files
Fix G004: replace logging f-strings with % formatting, remove G004 from suppression list
Agent-Logs-Url: https://github.com/GitHubSecurityLab/seclab-taskflow-agent/sessions/fc7d4cac-0cf0-4a55-b9a1-b00a172e1c03 Co-authored-by: kevinbackhouse <4358136+kevinbackhouse@users.noreply.github.com>
1 parent f271e43 commit 95dec56

9 files changed

Lines changed: 38 additions & 39 deletions

File tree

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ ignore = [
172172
# Style choices — deliberate project conventions
173173
"EM101", # Exception string literals
174174
"EM102", # Exception f-strings
175-
"G004", # Logging f-strings
176175
"T201", # print() used for user output
177176
"TRY003", # Raise with inline message strings
178177

src/seclab_taskflow_agent/agent.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,27 @@ def __init__(
7070

7171
async def on_agent_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext]) -> None:
7272
"""Called when an agent begins execution."""
73-
logging.debug(f"TaskRunHooks on_agent_start: {agent.name}")
73+
logging.debug("TaskRunHooks on_agent_start: %s", agent.name)
7474
if self._on_agent_start:
7575
await self._on_agent_start(context, agent)
7676

7777
async def on_agent_end(self, context: RunContextWrapper[TContext], agent: Agent[TContext], output: Any) -> None:
7878
"""Called when an agent finishes execution."""
79-
logging.debug(f"TaskRunHooks on_agent_end: {agent.name}")
79+
logging.debug("TaskRunHooks on_agent_end: %s", agent.name)
8080
if self._on_agent_end:
8181
await self._on_agent_end(context, agent, output)
8282

8383
async def on_tool_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool) -> None:
8484
"""Called before a tool invocation begins."""
85-
logging.debug(f"TaskRunHooks on_tool_start: {tool.name}")
85+
logging.debug("TaskRunHooks on_tool_start: %s", tool.name)
8686
if self._on_tool_start:
8787
await self._on_tool_start(context, agent, tool)
8888

8989
async def on_tool_end(
9090
self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool, result: str
9191
) -> None:
9292
"""Called after a tool invocation completes."""
93-
logging.debug(f"TaskRunHooks on_tool_end: {tool.name} ")
93+
logging.debug("TaskRunHooks on_tool_end: %s", tool.name)
9494
if self._on_tool_end:
9595
await self._on_tool_end(context, agent, tool, result)
9696

@@ -117,33 +117,33 @@ async def on_handoff(
117117
self, context: RunContextWrapper[TContext], agent: Agent[TContext], source: Agent[TContext]
118118
) -> None:
119119
"""Called when control is handed off from one agent to another."""
120-
logging.debug(f"TaskAgentHooks on_handoff: {source.name} -> {agent.name}")
120+
logging.debug("TaskAgentHooks on_handoff: %s -> %s", source.name, agent.name)
121121
if self._on_handoff:
122122
await self._on_handoff(context, agent, source)
123123

124124
async def on_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext]) -> None:
125125
"""Called when the agent starts processing."""
126-
logging.debug(f"TaskAgentHooks on_start: {agent.name}")
126+
logging.debug("TaskAgentHooks on_start: %s", agent.name)
127127
if self._on_start:
128128
await self._on_start(context, agent)
129129

130130
async def on_end(self, context: RunContextWrapper[TContext], agent: Agent[TContext], output: Any) -> None:
131131
"""Called when the agent finishes processing."""
132-
logging.debug(f"TaskAgentHooks on_end: {agent.name}")
132+
logging.debug("TaskAgentHooks on_end: %s", agent.name)
133133
if self._on_end:
134134
await self._on_end(context, agent, output)
135135

136136
async def on_tool_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool) -> None:
137137
"""Called before a tool invocation begins."""
138-
logging.debug(f"TaskAgentHooks on_tool_start: {tool.name}")
138+
logging.debug("TaskAgentHooks on_tool_start: %s", tool.name)
139139
if self._on_tool_start:
140140
await self._on_tool_start(context, agent, tool)
141141

142142
async def on_tool_end(
143143
self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool, result: str
144144
) -> None:
145145
"""Called after a tool invocation completes."""
146-
logging.debug(f"TaskAgentHooks on_tool_end: {tool.name}")
146+
logging.debug("TaskAgentHooks on_tool_end: %s", tool.name)
147147
if self._on_tool_end:
148148
await self._on_tool_end(context, agent, tool, result)
149149

src/seclab_taskflow_agent/mcp_lifecycle.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ def build_mcp_servers(
9797
if "command" in params:
9898

9999
def _print_out(line: str) -> None:
100-
logging.info(f"Streamable MCP Server stdout: {line}")
100+
logging.info("Streamable MCP Server stdout: %s", line)
101101

102102
def _print_err(line: str) -> None:
103-
logging.info(f"Streamable MCP Server stderr: {line}")
103+
logging.info("Streamable MCP Server stderr: %s", line)
104104

105105
server_proc = StreamableMCPThread(
106106
params["command"],
@@ -137,7 +137,7 @@ async def mcp_session_task(
137137
"""
138138
try:
139139
for entry in entries:
140-
logging.debug(f"Connecting mcp server: {entry.name}")
140+
logging.debug("Connecting mcp server: %s", entry.name)
141141
if entry.process is not None:
142142
entry.process.start()
143143
await entry.process.async_wait_for_connection(poll_interval=0.1)
@@ -148,17 +148,17 @@ async def mcp_session_task(
148148

149149
for entry in list(reversed(entries)):
150150
try:
151-
logging.debug(f"Starting cleanup for mcp server: {entry.name}")
151+
logging.debug("Starting cleanup for mcp server: %s", entry.name)
152152
await entry.server.cleanup()
153-
logging.debug(f"Cleaned up mcp server: {entry.name}")
153+
logging.debug("Cleaned up mcp server: %s", entry.name)
154154
if entry.process is not None:
155155
entry.process.stop()
156156
try:
157157
await asyncio.to_thread(entry.process.join_and_raise)
158158
except Exception as e:
159-
logging.warning(f"Streamable mcp server process exception: {e}")
159+
logging.warning("Streamable mcp server process exception: %s", e)
160160
except asyncio.CancelledError:
161-
logging.exception(f"Timeout on cleanup for mcp server: {entry.name}")
161+
logging.exception("Timeout on cleanup for mcp server: %s", entry.name)
162162
except RuntimeError:
163163
logging.exception("RuntimeError in mcp session task")
164164
except asyncio.CancelledError:

src/seclab_taskflow_agent/mcp_servers/codeql/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ def _get_source_prefix(database_path: Path, strip_leading_slash=True) -> str:
487487
source_prefix = source_prefix.lstrip("/")
488488
return source_prefix
489489
except (yaml.YAMLError, FileNotFoundError, KeyError) as e:
490-
logging.error(f"Error parsing sourceLocationPrefix: {e}")
490+
logging.error("Error parsing sourceLocationPrefix: %s", e)
491491
raise
492492

493493

src/seclab_taskflow_agent/mcp_utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def mcp_client_params(
166166
case "stdio":
167167
env = dict(sp.env) if sp.env else None
168168
args = list(sp.args) if sp.args else None
169-
logging.debug(f"Initializing toolbox: {tb}\nargs:\n{args}\nenv:\n{env}\n")
169+
logging.debug("Initializing toolbox: %s\nargs:\n%s\nenv:\n%s\n", tb, args, env)
170170
if env:
171171
for k, v in list(env.items()):
172172
try:
@@ -175,11 +175,11 @@ def mcp_client_params(
175175
logging.critical(e)
176176
logging.info("Assuming toolbox has default configuration available")
177177
del env[k]
178-
logging.debug(f"Tool call environment: {env}")
178+
logging.debug("Tool call environment: %s", env)
179179
if args:
180180
for i, v in enumerate(args):
181181
args[i] = swap_env(v)
182-
logging.debug(f"Tool call args: {args}")
182+
logging.debug("Tool call args: %s", args)
183183
server_params["command"] = sp.command
184184
server_params["args"] = args
185185
server_params["env"] = env
@@ -199,7 +199,7 @@ def mcp_client_params(
199199
if sp.command is not None:
200200
env = dict(sp.env) if sp.env else None
201201
args = list(sp.args) if sp.args else None
202-
logging.debug(f"Initializing streamable toolbox: {tb}\nargs:\n{args}\nenv:\n{env}\n")
202+
logging.debug("Initializing streamable toolbox: %s\nargs:\n%s\nenv:\n%s\n", tb, args, env)
203203
exe = shutil.which(sp.command)
204204
if exe is None:
205205
raise FileNotFoundError(f"Could not resolve path to {sp.command}")

src/seclab_taskflow_agent/prompt_parser.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ def parse_prompt_args(
5252
args = parser.parse_known_args(user_prompt.split(" ") if user_prompt else None)
5353
except SystemExit as e:
5454
if e.code == 2:
55-
logging.exception(f"User provided incomplete prompt: {user_prompt}")
55+
logging.exception("User provided incomplete prompt: %s", user_prompt)
5656
return None, None, None, None, "", help_msg
5757
except Exception:
58-
logging.exception(f"Failed to parse prompt: {user_prompt}")
58+
logging.exception("Failed to parse prompt: %s", user_prompt)
5959
return None, None, None, None, "", help_msg
6060
p = args[0].p.strip() if args[0].p else None
6161
t = args[0].t.strip() if args[0].t else None
@@ -65,7 +65,7 @@ def parse_prompt_args(
6565
if args[0].globals:
6666
for g in args[0].globals:
6767
if "=" not in g:
68-
logging.error(f"Invalid global variable format: {g}. Expected KEY=VALUE")
68+
logging.error("Invalid global variable format: %s. Expected KEY=VALUE", g)
6969
return None, None, None, None, "", help_msg
7070
key, value = g.split("=", 1)
7171
cli_globals[key.strip()] = value.strip()

src/seclab_taskflow_agent/runner.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,14 @@ async def _build_prompts_to_run(
197197
logging.critical("No last MCP tool result available")
198198
raise
199199
except json.JSONDecodeError as exc:
200-
logging.critical(f"Could not parse tool result as JSON: {last_mcp_tool_results[-1][:200]}")
200+
logging.critical("Could not parse tool result as JSON: %s", last_mcp_tool_results[-1][:200])
201201
raise ValueError("Tool result is not valid JSON") from exc
202202

203203
text = last_result.get("text", "")
204204
try:
205205
iterable_result = json.loads(text)
206206
except json.JSONDecodeError as exc:
207-
logging.critical(f"Could not parse result text: {text}")
207+
logging.critical("Could not parse result text: %s", text)
208208
raise ValueError("Result text is not valid JSON") from exc
209209
try:
210210
iter(iterable_result)
@@ -215,7 +215,7 @@ async def _build_prompts_to_run(
215215
if not iterable_result:
216216
await render_model_output("** 🤖❗MCP tool result iterable is empty!\n")
217217
else:
218-
logging.debug(f"Rendering templated prompts for results: {iterable_result}")
218+
logging.debug("Rendering templated prompts for results: %s", iterable_result)
219219
for value in iterable_result:
220220
try:
221221
rendered_prompt = render_template(
@@ -227,7 +227,7 @@ async def _build_prompts_to_run(
227227
)
228228
prompts_to_run.append(rendered_prompt)
229229
except jinja2.TemplateError as e:
230-
logging.error(f"Error rendering template for result {value}: {e}")
230+
logging.error("Error rendering template for result %s: %s", value, e)
231231
raise ValueError(f"Template rendering failed: {e}")
232232

233233
# Consume only after all prompts rendered successfully so that
@@ -408,15 +408,15 @@ async def _run_streamed() -> None:
408408
rate_limit_backoff = MAX_RATE_LIMIT_BACKOFF
409409
else:
410410
rate_limit_backoff += rate_limit_backoff
411-
logging.exception(f"Hit rate limit ... holding for {rate_limit_backoff}")
411+
logging.exception("Hit rate limit ... holding for %s", rate_limit_backoff)
412412
await asyncio.sleep(rate_limit_backoff)
413413

414414
await _run_streamed()
415415
complete = True
416416

417417
except MaxTurnsExceeded as e:
418418
await render_model_output(f"** 🤖❗ Max Turns Reached: {e}\n", async_task=async_task, task_id=task_id)
419-
logging.exception(f"Exceeded max_turns: {max_turns}")
419+
logging.exception("Exceeded max_turns: %s", max_turns)
420420
except AgentsException as e:
421421
await render_model_output(f"** 🤖❗ Agent Exception: {e}\n", async_task=async_task, task_id=task_id)
422422
logging.exception("Agent Exception")
@@ -576,7 +576,7 @@ async def on_handoff_hook(context: RunContextWrapper[TContext], agent: Agent[TCo
576576
inputs_dict=inputs,
577577
)
578578
except jinja2.TemplateError as e:
579-
logging.error(f"Template rendering error: {e}")
579+
logging.error("Template rendering error: %s", e)
580580
raise ValueError(f"Failed to render prompt template: {e}") from e
581581

582582
with TmpEnv(env):
@@ -657,7 +657,7 @@ async def _deploy(ra: dict, pp: str) -> bool:
657657
complete = True
658658
for result in task_results:
659659
if isinstance(result, Exception):
660-
logging.error(f"Caught exception in Gather: {result}")
660+
logging.error("Caught exception in Gather: %s", result)
661661
result = False
662662
complete = result and complete
663663
return complete
@@ -690,13 +690,13 @@ async def _deploy(ra: dict, pp: str) -> bool:
690690
f"** 🤖🔄 Task {task_name!r} failed: {exc}\n"
691691
f"** 🤖🔄 Retrying in {backoff}s ({remaining} attempts left)\n"
692692
)
693-
logging.warning(f"Task {task_name!r} attempt {attempt + 1} failed: {exc}")
693+
logging.warning("Task %r attempt %s failed: %s", task_name, attempt + 1, exc)
694694
await asyncio.sleep(backoff)
695695
else:
696-
logging.error(f"Task {task_name!r} failed after {TASK_RETRY_LIMIT} attempts: {exc}")
696+
logging.error("Task %r failed after %s attempts: %s", task_name, TASK_RETRY_LIMIT, exc)
697697
except Exception as exc:
698698
last_task_error = exc
699-
logging.error(f"Task {task_name!r} failed (non-retriable): {exc}")
699+
logging.error("Task %r failed (non-retriable): %s", task_name, exc)
700700
break
701701

702702
# If all retries exhausted with an exception, save and re-raise

src/seclab_taskflow_agent/session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def save(self) -> Path:
8080
self.updated_at = datetime.now(timezone.utc).isoformat()
8181
path = self.file_path
8282
path.write_text(self.model_dump_json(indent=2))
83-
logging.debug(f"Session checkpoint saved: {path}")
83+
logging.debug("Session checkpoint saved: %s", path)
8484
return path
8585

8686
def record_task(
@@ -132,5 +132,5 @@ def list_sessions(cls) -> list[TaskflowSession]:
132132
try:
133133
sessions.append(cls.model_validate_json(f.read_text()))
134134
except Exception:
135-
logging.warning(f"Skipping corrupt session file: {f}")
135+
logging.warning("Skipping corrupt session file: %s", f)
136136
return sessions

src/seclab_taskflow_agent/shell_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def shell_command_to_string(cmd: list[str]) -> str:
1818
Raises:
1919
RuntimeError: If the command exits with a non-zero return code.
2020
"""
21-
logging.info(f"Executing: {cmd}")
21+
logging.info("Executing: %s", cmd)
2222
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
2323
stdout, stderr = p.communicate()
2424
p.wait()

0 commit comments

Comments
 (0)