Skip to content

Commit 712c308

Browse files
Merge pull request #255 from GitHubSecurityLab/copilot/g004-fix-linter-error-again
Enable Ruff G004 and migrate logging calls to lazy formatting
2 parents 3cfa5b2 + 39708d3 commit 712c308

10 files changed

Lines changed: 40 additions & 39 deletions

File tree

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ ignore = [
183183
# Style choices — deliberate project conventions
184184
"EM101", # Exception string literals
185185
"EM102", # Exception f-strings
186-
"G004", # Logging f-strings
187186
"T201", # print() used for user output
188187
"TRY003", # Raise with inline message strings
189188

src/seclab_taskflow_agent/_stream.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ async def drive_backend_stream(
135135
rate_limit_backoff = max_rate_limit_backoff
136136
else:
137137
rate_limit_backoff += rate_limit_backoff
138-
logging.exception(f"Hit rate limit ... holding for {rate_limit_backoff}")
138+
logging.exception("Hit rate limit ... holding for %s", rate_limit_backoff)
139139
await asyncio.sleep(rate_limit_backoff)
140140

141141
if last_rate_limit_exc is not None: # pragma: no cover - loop always returns/raises above

src/seclab_taskflow_agent/agent.py

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

6262
async def on_agent_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext]) -> None:
6363
"""Called when an agent begins execution."""
64-
logging.debug(f"TaskRunHooks on_agent_start: {agent.name}")
64+
logging.debug("TaskRunHooks on_agent_start: %s", agent.name)
6565
if self._on_agent_start:
6666
await self._on_agent_start(context, agent)
6767

6868
async def on_agent_end(self, context: RunContextWrapper[TContext], agent: Agent[TContext], output: Any) -> None:
6969
"""Called when an agent finishes execution."""
70-
logging.debug(f"TaskRunHooks on_agent_end: {agent.name}")
70+
logging.debug("TaskRunHooks on_agent_end: %s", agent.name)
7171
if self._on_agent_end:
7272
await self._on_agent_end(context, agent, output)
7373

7474
async def on_tool_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool) -> None:
7575
"""Called before a tool invocation begins."""
76-
logging.debug(f"TaskRunHooks on_tool_start: {tool.name}")
76+
logging.debug("TaskRunHooks on_tool_start: %s", tool.name)
7777
if self._on_tool_start:
7878
await self._on_tool_start(context, agent, tool)
7979

8080
async def on_tool_end(
8181
self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool, result: str
8282
) -> None:
8383
"""Called after a tool invocation completes."""
84-
logging.debug(f"TaskRunHooks on_tool_end: {tool.name} ")
84+
logging.debug("TaskRunHooks on_tool_end: %s ", tool.name)
8585
if self._on_tool_end:
8686
await self._on_tool_end(context, agent, tool, result)
8787

@@ -108,33 +108,33 @@ async def on_handoff(
108108
self, context: RunContextWrapper[TContext], agent: Agent[TContext], source: Agent[TContext]
109109
) -> None:
110110
"""Called when control is handed off from one agent to another."""
111-
logging.debug(f"TaskAgentHooks on_handoff: {source.name} -> {agent.name}")
111+
logging.debug("TaskAgentHooks on_handoff: %s -> %s", source.name, agent.name)
112112
if self._on_handoff:
113113
await self._on_handoff(context, agent, source)
114114

115115
async def on_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext]) -> None:
116116
"""Called when the agent starts processing."""
117-
logging.debug(f"TaskAgentHooks on_start: {agent.name}")
117+
logging.debug("TaskAgentHooks on_start: %s", agent.name)
118118
if self._on_start:
119119
await self._on_start(context, agent)
120120

121121
async def on_end(self, context: RunContextWrapper[TContext], agent: Agent[TContext], output: Any) -> None:
122122
"""Called when the agent finishes processing."""
123-
logging.debug(f"TaskAgentHooks on_end: {agent.name}")
123+
logging.debug("TaskAgentHooks on_end: %s", agent.name)
124124
if self._on_end:
125125
await self._on_end(context, agent, output)
126126

127127
async def on_tool_start(self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool) -> None:
128128
"""Called before a tool invocation begins."""
129-
logging.debug(f"TaskAgentHooks on_tool_start: {tool.name}")
129+
logging.debug("TaskAgentHooks on_tool_start: %s", tool.name)
130130
if self._on_tool_start:
131131
await self._on_tool_start(context, agent, tool)
132132

133133
async def on_tool_end(
134134
self, context: RunContextWrapper[TContext], agent: Agent[TContext], tool: Tool, result: str
135135
) -> None:
136136
"""Called after a tool invocation completes."""
137-
logging.debug(f"TaskAgentHooks on_tool_end: {tool.name}")
137+
logging.debug("TaskAgentHooks on_tool_end: %s", tool.name)
138138
if self._on_tool_end:
139139
await self._on_tool_end(context, agent, tool, result)
140140

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
@@ -167,7 +167,7 @@ def mcp_client_params(
167167
case "stdio":
168168
env = dict(sp.env) if sp.env else None
169169
args = list(sp.args) if sp.args else None
170-
logging.debug(f"Initializing toolbox: {tb}\nargs:\n{args}\nenv:\n{env}\n")
170+
logging.debug("Initializing toolbox: %s\nargs:\n%s\nenv:\n%s\n", tb, args, env)
171171
if env:
172172
for k, v in list(env.items()):
173173
try:
@@ -182,11 +182,11 @@ def mcp_client_params(
182182
"http_proxy", "https_proxy", "no_proxy"):
183183
if proxy_var not in env and proxy_var in os.environ:
184184
env[proxy_var] = os.environ[proxy_var]
185-
logging.debug(f"Tool call environment: {env}")
185+
logging.debug("Tool call environment: %s", env)
186186
if args:
187187
for i, v in enumerate(args):
188188
args[i] = swap_env(v)
189-
logging.debug(f"Tool call args: {args}")
189+
logging.debug("Tool call args: %s", args)
190190
server_params["command"] = sp.command
191191
server_params["args"] = args
192192
server_params["env"] = env
@@ -206,7 +206,7 @@ def mcp_client_params(
206206
if sp.command is not None:
207207
env = dict(sp.env) if sp.env else None
208208
args = list(sp.args) if sp.args else None
209-
logging.debug(f"Initializing streamable toolbox: {tb}\nargs:\n{args}\nenv:\n{env}\n")
209+
logging.debug("Initializing streamable toolbox: %s\nargs:\n%s\nenv:\n%s\n", tb, args, env)
210210
exe = shutil.which(sp.command)
211211
if exe is None:
212212
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: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,14 @@ async def _build_prompts_to_run(
204204
logging.critical("No last MCP tool result available")
205205
raise
206206
except json.JSONDecodeError as exc:
207-
logging.critical(f"Could not parse tool result as JSON: {last_mcp_tool_results[-1][:200]}")
207+
logging.critical("Could not parse tool result as JSON: %s", last_mcp_tool_results[-1][:200])
208208
raise ValueError("Tool result is not valid JSON") from exc
209209

210210
text = last_result.get("text", "")
211211
try:
212212
iterable_result = json.loads(text)
213213
except json.JSONDecodeError as exc:
214-
logging.critical(f"Could not parse result text: {text}")
214+
logging.critical("Could not parse result text: %s", text)
215215
raise ValueError("Result text is not valid JSON") from exc
216216
try:
217217
iter(iterable_result)
@@ -222,7 +222,7 @@ async def _build_prompts_to_run(
222222
if not iterable_result:
223223
await render_model_output("** 🤖❗MCP tool result iterable is empty!\n")
224224
else:
225-
logging.debug(f"Rendering templated prompts for results: {iterable_result}")
225+
logging.debug("Rendering templated prompts for results: %s", iterable_result)
226226
for value in iterable_result:
227227
try:
228228
rendered_prompt = render_template(
@@ -234,7 +234,7 @@ async def _build_prompts_to_run(
234234
)
235235
prompts_to_run.append(rendered_prompt)
236236
except jinja2.TemplateError as e:
237-
logging.error(f"Error rendering template for result {value}: {e}")
237+
logging.error("Error rendering template for result %s: %s", value, e)
238238
raise ValueError(f"Template rendering failed: {e}")
239239

240240
# Consume only after all prompts rendered successfully so that
@@ -429,7 +429,7 @@ async def deploy_task_agents(
429429

430430
except BackendMaxTurnsError as e:
431431
await render_model_output(f"** 🤖❗ Max Turns Reached: {e}\n", async_task=async_task, task_id=task_id)
432-
logging.exception(f"Exceeded max_turns: {max_turns}")
432+
logging.exception("Exceeded max_turns: %s", max_turns)
433433
except BackendUnexpectedError as e:
434434
await render_model_output(f"** 🤖❗ Agent Exception: {e}\n", async_task=async_task, task_id=task_id)
435435
logging.exception("Agent Exception")
@@ -625,7 +625,7 @@ async def on_handoff_hook(context: RunContextWrapper[TContext], agent: Agent[TCo
625625
inputs_dict=inputs,
626626
)
627627
except jinja2.TemplateError as e:
628-
logging.error(f"Template rendering error: {e}")
628+
logging.error("Template rendering error: %s", e)
629629
raise ValueError(f"Failed to render prompt template: {e}") from e
630630

631631
with TmpEnv(env, context={"globals": global_variables}):
@@ -707,7 +707,7 @@ async def _deploy(ra: dict, pp: str) -> bool:
707707
complete = True
708708
for result in task_results:
709709
if not isinstance(result, bool):
710-
logging.error(f"Caught exception in Gather: {result}", exc_info=result)
710+
logging.error("Caught exception in Gather: %s", result, exc_info=result)
711711
result = False
712712
complete = result and complete
713713
return complete
@@ -740,13 +740,15 @@ async def _deploy(ra: dict, pp: str) -> bool:
740740
f"** 🤖🔄 Task {task_name!r} failed: {exc}\n"
741741
f"** 🤖🔄 Retrying in {backoff}s ({remaining} attempts left)\n"
742742
)
743-
logging.warning(f"Task {task_name!r} attempt {attempt + 1} failed: {exc}")
743+
logging.warning("Task %r attempt %s failed: %s", task_name, attempt + 1, exc)
744744
await asyncio.sleep(backoff)
745745
else:
746-
logging.error(f"Task {task_name!r} failed after {TASK_RETRY_LIMIT} attempts: {exc}")
746+
logging.error(
747+
"Task %r failed after %s attempts: %s", task_name, TASK_RETRY_LIMIT, exc
748+
)
747749
except Exception as exc:
748750
last_task_error = exc
749-
logging.error(f"Task {task_name!r} failed (non-retriable): {exc}")
751+
logging.error("Task %r failed (non-retriable): %s", task_name, exc)
750752
break
751753

752754
# 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)