Skip to content

feat: improve download APIs and task logging - #554

Open
hect0x7 wants to merge 3 commits into
masterfrom
dev
Open

feat: improve download APIs and task logging#554
hect0x7 wants to merge 3 commits into
masterfrom
dev

Conversation

@hect0x7

@hect0x7 hect0x7 commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Clarify callback and batch exception contracts, add task-scoped logging across sync and async workers, and update the mobile API version.

Summary by CodeRabbit

  • New Features
    • Added task-aware logging with stable per-download correlation for clearer troubleshooting in concurrent runs.
    • Download features and plugins can access the current task context.
  • Bug Fixes
    • Improved consistency of task-context propagation across synchronous, asynchronous, threaded, and decode-pool execution.
  • Documentation
    • Clarified download event customization, batch partial-failure behavior, and concurrent logging context usage; standardized “event” terminology.
  • Breaking Changes
    • Removed public callback parameters from single-album/single-photo download APIs (sync/async); check_exception is now keyword-only.
  • Chores
    • Updated CLI imports to use the supported module; adjusted related docs/tests.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds task-local context propagation across synchronous, asynchronous, threaded, and plugin execution paths. Public download callbacks are removed, exception options become keyword-only, logs include task identifiers, the deprecated CLI shim is removed, and documentation and tests are updated.

Changes

Task Context and Download APIs

Layer / File(s) Summary
Context foundation and public API contract
src/jmcomic/jm_task_context.py, src/jmcomic/api.py, src/jmcomic/__init__.py, tests/jmcomic/*, assets/docs/sources/tutorial/*, assets/docs/sources/option_file_syntax.md, README.md
Adds ContextVar-based task context management, removes callback parameters from public download APIs, makes exception options keyword-only, preserves batch failure collection, and updates related documentation.
Context propagation across executors
src/jmcomic/jm_async_downloader.py, src/jmcomic/jm_client_impl.py, src/jmcomic/jm_downloader.py, src/jmcomic/jm_feature.py, src/jmcomic/jm_plugin.py
Binds task context across decode pools, thread pools, downloader branches, proxy fetches, plugins, and feature invocations.
Contextual logging and validation
src/jmcomic/jm_config.py, assets/docs/sources/tutorial/11_log_custom.md, tests/test_jmcomic/test_jm_task_context.py
Adds task-context log prefixes and formatter support, documents logging filters and concurrent task context, and tests formatting, propagation, and isolation behavior.
CLI module migration
src/jmcomic/cl.py, assets/docs/sources/api/command-line.md, tests/test_jmcomic/test_jm_cli.py, usage/workflow_download.py
Removes the deprecated jmcomic.cl shim and changes CLI references and imports to jmcomic.cli.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant DownloadAPI
  participant Executor
  participant Logger
  Caller->>DownloadAPI: start download
  DownloadAPI->>DownloadAPI: set jm_task_context
  DownloadAPI->>Executor: run bound task
  Executor-->>Logger: emit contextual record
  Logger-->>Caller: formatted task-aware log
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: download API updates and task logging improvements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Clarify callback and batch exception contracts, add task-scoped logging across sync and async workers, and update the mobile API version.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/docs/sources/tutorial/11_log_custom.md`:
- Line 117: Update the formatter assignment in the custom logging example to
avoid indexing jm_logger.handlers when no handlers are configured. Reuse the
first handler’s formatter when available, and otherwise apply a valid formatter
fallback before registering TaskLogHandler.

In `@assets/docs/sources/tutorial/4_module_custom.md`:
- Around line 20-22: Update the after_album override in the tutorial example to
delegate to JmDownloader.after_album by calling super().after_album(album),
while retaining the existing custom print behavior and choosing an appropriate
call order.

In `@README.md`:
- Line 241: Update the README bullet describing download event callbacks to
state that users must customize the behavior through a custom Downloader, such
as by subclassing or configuring it, rather than implying a public callback
parameter.

In `@src/jmcomic/__init__.py`:
- Line 7: Replace the star import from jm_task_context in the package
initializer with an explicit import of JM_TASK_CONTEXT, jm_task_context,
get_jm_task_context, and bind_jm_task_context, preserving the existing
package-level API.

In `@src/jmcomic/jm_task_context.py`:
- Around line 41-45: Update bind_jm_task_context to validate func with
callable(func) before async detection or wrapping, rejecting non-callable
targets immediately. Retain the existing __call__ inspection only for
identifying asynchronous callable objects, and preserve the current TypeError
behavior for unsupported async callables.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 62f4de3f-407c-4dcd-b46a-c5266f1923e5

📥 Commits

Reviewing files that changed from the base of the PR and between 2d03218 and f2cd00f.

📒 Files selected for processing (18)
  • README.md
  • assets/docs/sources/option_file_syntax.md
  • assets/docs/sources/tutorial/0_common_usage.md
  • assets/docs/sources/tutorial/11_log_custom.md
  • assets/docs/sources/tutorial/13_export_and_feature.md
  • assets/docs/sources/tutorial/4_module_custom.md
  • src/jmcomic/__init__.py
  • src/jmcomic/api.py
  • src/jmcomic/jm_async_downloader.py
  • src/jmcomic/jm_client_impl.py
  • src/jmcomic/jm_config.py
  • src/jmcomic/jm_downloader.py
  • src/jmcomic/jm_feature.py
  • src/jmcomic/jm_plugin.py
  • src/jmcomic/jm_task_context.py
  • tests/test_jmcomic/test_jm_api.py
  • tests/test_jmcomic/test_jm_async_api.py
  • tests/test_jmcomic/test_jm_task_context.py
💤 Files with no reviewable changes (1)
  • tests/test_jmcomic/test_jm_async_api.py



handler = TaskLogHandler()
handler.setFormatter(jm_logger.handlers[0].formatter) # 复用jmcomic默认 Handler 的日志格式,你也可以自定义日志格式

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Avoid assuming a default handler exists.

This example indexes jm_logger.handlers[0], but the customization guide also supports clearing or replacing handlers. With no handlers configured, the example raises IndexError before registering TaskLogHandler; use a formatter fallback instead.

Proposed fallback
 handler = TaskLogHandler()
-handler.setFormatter(jm_logger.handlers[0].formatter)
+formatter = next(
+    (item.formatter for item in jm_logger.handlers if item.formatter is not None),
+    logging.Formatter('%(message)s'),
+)
+handler.setFormatter(formatter)
 jm_logger.addHandler(handler)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
handler.setFormatter(jm_logger.handlers[0].formatter) # 复用jmcomic默认 Handler 的日志格式,你也可以自定义日志格式
formatter = next(
(item.formatter for item in jm_logger.handlers if item.formatter is not None),
logging.Formatter('%(message)s'),
)
handler.setFormatter(formatter)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/docs/sources/tutorial/11_log_custom.md` at line 117, Update the
formatter assignment in the custom logging example to avoid indexing
jm_logger.handlers when no handlers are configured. Reuse the first handler’s
formatter when available, and otherwise apply a valid formatter fallback before
registering TaskLogHandler.

Comment on lines 20 to 22
def after_album(self, album: JmAlbumDetail):
print(f'album下载完毕: {album}')
pass

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve the base after-album lifecycle.

This override replaces JmDownloader.after_album and never delegates to it. Users copying the example can therefore disable the built-in after-album plugin/Feature pipeline. Call super().after_album(album) before or after the custom behavior, depending on the desired ordering.

Proposed fix
         def after_album(self, album: JmAlbumDetail):
+            super().after_album(album)
             print(f'album下载完毕: {album}')
-            pass
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def after_album(self, album: JmAlbumDetail):
print(f'album下载完毕: {album}')
pass
def after_album(self, album: JmAlbumDetail):
super().after_album(album)
print(f'album下载完毕: {album}')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/docs/sources/tutorial/4_module_custom.md` around lines 20 - 22, Update
the after_album override in the tutorial example to delegate to
JmDownloader.after_album by calling super().after_album(album), while retaining
the existing custom print behavior and choosing an appropriate call order.

Comment thread README.md
- **可扩展性强**

- 支持自定义本子/章节/图片下载前后的回调函数
- 支持自定义本子/章节/图片下载前后事件的回调函数

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clarify that download events require a custom Downloader.

This bullet still suggests that users can customize download callbacks directly, while the updated API contract removes the public callback parameter. State explicitly that event behavior is customized by subclassing/configuring Downloader.

Proposed wording
-  - 支持自定义本子/章节/图片下载前后事件的回调函数
+  - 支持通过自定义 Downloader 响应本子/章节/图片下载前后事件(公开下载 API 不接收 callback 参数)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- 支持自定义本子/章节/图片下载前后事件的回调函数
- 支持通过自定义 Downloader 响应本子/章节/图片下载前后事件(公开下载 API 不接收 callback 参数)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 241, Update the README bullet describing download event
callbacks to state that users must customize the behavior through a custom
Downloader, such as by subclassing or configuring it, rather than implying a
public callback parameter.

Comment thread src/jmcomic/__init__.py

__version__ = '2.7.2'

from .jm_task_context import *

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)__init__\.py$|jm_task_context'

echo "== __init__ around line =="
cat -n src/jmcomic/__init__.py | sed -n '1,80p'

echo "== jm_task_context outline =="
ast-grep outline src/jmcomic/jm_task_context.py 2>/dev/null || true
echo "== jm_task_context relevant symbols =="
rg -n "^(JM_TASK_CONTEXT|bind_jm_task_context|get_jm_task_context|jm_task_context)\b|__all__" src/jmcomic/jm_task_context.py

echo "== imports of jm_task_context from package root / globals =="
rg -n "from \. jm_task_context import \*|from \.jm_task_context import|get_jm_task_context|JM_TASK_CONTEXT|bind_jm_task_context|jm_task_context" src/jmcomic/__init__.py src/jmcomic/jm_task_context.py

Repository: hect0x7/JMComic-Crawler-Python

Length of output: 3802


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file listing =="
git ls-files | grep -E '(^|/)__init__\.py$|jm_task_context|setup|pyproject|poetry|requirements' || true

echo "== __init__ =="
cat -n src/jmcomic/__init__.py | sed -n '1,120p'

echo "== task context relevant =="
rg -n "^(def |class |JM_TASK_CONTEXT|bind_jm_task_context|get_jm_task_context|jm_task_context|__all__|= .*Task.*|= .*Context.*|@)" src/jmcomic/jm_task_context.py

Repository: hect0x7/JMComic-Crawler-Python

Length of output: 2267


Replace the task-context star import with explicit re-exports.

jm_task_context.__all__ exposes JM_TASK_CONTEXT, jm_task_context, get_jm_task_context, and bind_jm_task_context; importing those names explicitly keeps the same package-level API and avoids F403/static-analysis ambiguity.

Proposed fix
-from .jm_task_context import *
+from .jm_task_context import (
+    JM_TASK_CONTEXT,
+    bind_jm_task_context,
+    get_jm_task_context,
+    jm_task_context,
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from .jm_task_context import *
from .jm_task_context import (
JM_TASK_CONTEXT,
bind_jm_task_context,
get_jm_task_context,
jm_task_context,
)
🧰 Tools
🪛 Ruff (0.16.0)

[error] 7-7: from .jm_task_context import * used; unable to detect undefined names

(F403)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jmcomic/__init__.py` at line 7, Replace the star import from
jm_task_context in the package initializer with an explicit import of
JM_TASK_CONTEXT, jm_task_context, get_jm_task_context, and bind_jm_task_context,
preserving the existing package-level API.

Source: Linters/SAST tools

Comment on lines +41 to +45
def bind_jm_task_context(func: Callable, context: Optional[Mapping] = None) -> Callable:
"""Bind a synchronous callable to a snapshot of the current task context."""
if (inspect.iscoroutinefunction(func)
or inspect.iscoroutinefunction(getattr(func, '__call__', None))):
raise TypeError('bind_jm_task_context only supports synchronous callables')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the relevant file and its context.
fd -a 'jm_task_context.py' . || true
file="$(fd 'jm_task_context.py' . | head -n 1 || true)"
if [ -n "${file:-}" ]; then
  echo "== file: $file =="
  wc -l "$file"
  echo
  sed -n '1,180p' "$file" | cat -n
fi

echo
echo "== references to bind_jm_task_context =="
rg -n "bind_jm_task_context|call_async|executor" . --glob '!**/.git/**' || true

echo
echo "== Python probe: current callable/check shape without repository execution =="
python3 - <<'PY'
import inspect
import types

def bind_jm_task_context_current(func, context=None):
    if (inspect.iscoroutinefunction(func)
            or inspect.iscoroutinefunction(getattr(func, '__call__', None))):
        raise TypeError('bind_jm_task_context only supports synchronous callables')
    def wrapped(*a, **kw):
        print("wrapped executed with", a, kw)
    return wrapped

def bound_func():
    return None

class AsyncCallable:
    async def __call__(self, value):
        return value

cases = [None, 123, [], lambda: None, bound_func, AsyncCallable()]
for case in cases:
    try:
        wrapped = bind_jm_task_context_current(case)
        print(type(case).__name__, "bound without error")
        try:
            wrapped()
        except Exception as e:
            print("  execution failure:", type(e).__name__, str(e))
    except Exception as e:
        print(type(case).__name__, "binding failure:", type(e).__name__, str(e))

PY

Repository: hect0x7/JMComic-Crawler-Python

Length of output: 7846


Fail fast for non-callable targets.

bind_jm_task_context currently accepts None and other non-callables, which only fail when wrapped invokes func. Add a callable(func) guard before accepting the target, while keeping the __call__ inspection only for detecting async callable objects.

🧰 Tools
🪛 Ruff (0.16.0)

[warning] 44-44: Using hasattr(x, "__call__") to test if x is callable is unreliable. Use callable(x) for consistent results.

(B004)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jmcomic/jm_task_context.py` around lines 41 - 45, Update
bind_jm_task_context to validate func with callable(func) before async detection
or wrapping, rejecting non-callable targets immediately. Retain the existing
__call__ inspection only for identifying asynchronous callable objects, and
preserve the current TypeError behavior for unsupported async callables.

Source: Linters/SAST tools

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/jmcomic/jm_config.py`:
- Line 612: Update the docstring for the ANSI-colored log formatter to replace
the fullwidth comma with an ASCII comma, preserving the existing wording and
behavior so Ruff’s RUF002 check passes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e859f80d-a09f-4951-b6c7-450765bd029c

📥 Commits

Reviewing files that changed from the base of the PR and between f2cd00f and e39c191.

📒 Files selected for processing (18)
  • README.md
  • assets/docs/sources/option_file_syntax.md
  • assets/docs/sources/tutorial/0_common_usage.md
  • assets/docs/sources/tutorial/11_log_custom.md
  • assets/docs/sources/tutorial/13_export_and_feature.md
  • assets/docs/sources/tutorial/4_module_custom.md
  • src/jmcomic/__init__.py
  • src/jmcomic/api.py
  • src/jmcomic/jm_async_downloader.py
  • src/jmcomic/jm_client_impl.py
  • src/jmcomic/jm_config.py
  • src/jmcomic/jm_downloader.py
  • src/jmcomic/jm_feature.py
  • src/jmcomic/jm_plugin.py
  • src/jmcomic/jm_task_context.py
  • tests/test_jmcomic/test_jm_api.py
  • tests/test_jmcomic/test_jm_async_api.py
  • tests/test_jmcomic/test_jm_task_context.py
💤 Files with no reviewable changes (1)
  • tests/test_jmcomic/test_jm_async_api.py
🚧 Files skipped from review as they are similar to previous changes (11)
  • README.md
  • src/jmcomic/jm_plugin.py
  • src/jmcomic/jm_feature.py
  • src/jmcomic/jm_client_impl.py
  • src/jmcomic/jm_downloader.py
  • assets/docs/sources/option_file_syntax.md
  • assets/docs/sources/tutorial/13_export_and_feature.md
  • assets/docs/sources/tutorial/0_common_usage.md
  • assets/docs/sources/tutorial/4_module_custom.md
  • assets/docs/sources/tutorial/11_log_custom.md
  • src/jmcomic/jm_async_downloader.py

Comment thread src/jmcomic/jm_config.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/jmcomic/jm_config.py`:
- Line 23: Update the comment near the task_context logging logic in
jm_config.py by replacing both fullwidth commas with ASCII commas, resolving the
remaining RUF003 lint violation without changing the code behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ac8cb86d-a8a0-47ed-ac2b-4a2924e8179b

📥 Commits

Reviewing files that changed from the base of the PR and between e39c191 and 0ecfb14.

📒 Files selected for processing (6)
  • assets/docs/sources/api/command-line.md
  • src/jmcomic/cl.py
  • src/jmcomic/jm_config.py
  • tests/test_jmcomic/test_jm_cli.py
  • tests/test_jmcomic/test_jm_task_context.py
  • usage/workflow_download.py
💤 Files with no reviewable changes (1)
  • src/jmcomic/cl.py

Comment thread src/jmcomic/jm_config.py
fields = []
task_id = context.get('task_id')
if task_id is None:
# 没有 task_id 时,默认不打印 task_context,保持日志简洁

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the remaining RUF003 lint violation.

Line 23 contains two fullwidth commas; replace them with ASCII commas so lint passes.

Proposed fix
-            # 没有 task_id 时,默认不打印 task_context,保持日志简洁
+            # 没有 task_id 时, 默认不打印 task_context, 保持日志简洁
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# 没有 task_id 时默认不打印 task_context保持日志简洁
# 没有 task_id 时, 默认不打印 task_context, 保持日志简洁
🧰 Tools
🪛 Ruff (0.16.0)

[warning] 23-23: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)


[warning] 23-23: Comment contains ambiguous (FULLWIDTH COMMA). Did you mean , (COMMA)?

(RUF003)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jmcomic/jm_config.py` at line 23, Update the comment near the
task_context logging logic in jm_config.py by replacing both fullwidth commas
with ASCII commas, resolving the remaining RUF003 lint violation without
changing the code behavior.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant