The import blocks hold only imports

`E402` read as seventeen deliberate late imports and was in fact two accidents.
A module constant had settled into the middle of `packet_viewer`'s import block
(`_BODY_CACHE_MAX`, now below it), and ten test modules put their `_FIXTURE`
path or a small helper above the last import — the `tests.conftest` screen
reader, which now joins the block it belonged to.

`B008` is the opposite case: all six are Typer declaring a CLI parameter by
calling `Argument`/`Option` in the default, which is the framework's API and
cannot be written another way in this style. The objects it returns are inert
sentinels no command mutates — exactly the thing `extend-immutable-calls` is
for, so the rule now knows about them instead of being silenced per line.

`.claude` leaves the lint's reach: those are helper scripts for the skills, not
package code, and CI has no reason to gate on them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jean-Pierre MartineauandClaude Opus 5 committed 2026-09-06 20:17:12 -04:00
1 parent e9a4f644d8
commit ca0023f5b7
12 files changed
+20 -13

No files matched your search

+3 -3
View File
@@ -53,9 +53,6 @@ from ..core.models import NODE_TYPE_LABELS, Observation, utcnow
from ..services.trace_runner import NodeResolver
from .map_render import _SELF, _UNKNOWN
from .menus import SEP_COMPACT, SEP_ROOMY
#: Composed packet cards the viewer memoizes (a few pages either side of the view).
_BODY_CACHE_MAX = 8
from .pathgraph import PathLayer, render_path_graph, revisited_hops
from .pathline import PathLine, path_line
from .theme import glyph, name_style, snr_style
@@ -75,6 +72,9 @@ from .widgets import (
route_graph_style,
)
#: Composed packet cards the viewer memoizes (a few pages either side of the view).
_BODY_CACHE_MAX = 8
#: Friendly gloss for a raw packet's parsed payload class (mirrors the meshcore
#: library's own ``PAYLOAD_TYPENAMES``), shown on a ``packet`` entry's "class" row.
_PAYLOAD_GLOSS = {
+7
View File
@@ -43,6 +43,8 @@ packages = ["meshterm"]
[tool.ruff]
line-length = 100
target-version = "py310"
# Helper scripts for the Claude skills; they are not part of the package.
extend-exclude = [".claude"]
[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "D"]
@@ -51,6 +53,11 @@ ignore = ["D203", "D213"] # pick one blank-line-before-class / multi-line-summa
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.ruff.lint.flake8-bugbear]
# Typer declares CLI parameters by calling these in the default; the objects they
# return are inert sentinels the command never mutates, which is what B008 guards.
extend-immutable-calls = ["typer.Argument", "typer.Option"]
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
+1 -1
View File
@@ -41,11 +41,11 @@ from meshterm.ui.marks import MASK_MARK
from meshterm.ui.theme import active_theme
from meshterm.ui.tui.prompt import TypedConfirmDialog
from meshterm.ui.tui.screen import CANCEL
from tests.conftest import plain as _plain # THE strip-and-join screen reader
_ANSI = re.compile(r"\x1b\[[0-9;]*m")
from tests.conftest import plain as _plain # THE strip-and-join screen reader
class _Fut:
+1 -1
View File
@@ -16,6 +16,7 @@ from meshterm.core.models import Observation, utcnow
from meshterm.persistence.repository import Repository
from meshterm.services.monitor_service import ACTIVITY_BUCKETS
from meshterm.ui.dashboard_screen import DashboardScreen
from tests.conftest import plain as _plain # THE strip-and-join screen reader
class _FakeSession:
@@ -46,7 +47,6 @@ def _obs(node="a1b2", kind="advert", snr=5.0, rssi=-90.0, age_s=0, **extra) -> O
)
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _stripped(lines: list[str]) -> list[str]:
+1 -1
View File
@@ -34,6 +34,7 @@ from meshterm.ui.trace_screen import (
snr_bar,
)
from meshterm.ui.tx_screen import TxSweepScreen
from tests.conftest import plain as _plain # THE strip-and-join screen reader
# The slim meter's fill glyphs (the SNR bar draws through the shared braille meter).
_BAR_FULL, _BAR_HALF = _METER_SLIM
@@ -79,7 +80,6 @@ def _trace(*snrs: float, success: bool = True, target: str = "Alice") -> TraceRe
)
from tests.conftest import plain as _plain # THE strip-and-join screen reader
# --- snr_bar -------------------------------------------------------------------
+1 -1
View File
@@ -14,6 +14,7 @@ from rich.cells import cell_len
from meshterm.core.events import MeshEvent
from meshterm.core.models import Ack, Message, Observation, utcnow
from meshterm.ui.livefeed_screen import _ICON_LANE, LiveFeedScreen
from tests.conftest import plain as _plain # THE strip-and-join screen reader
class _FakeSession:
@@ -71,7 +72,6 @@ def _obs(node="a1b2", kind="advert", snr=5.0, rssi=-90.0, age_s=0, **extra) -> O
)
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _stripped(lines: list[str]) -> list[str]:
+1 -1
View File
@@ -31,12 +31,12 @@ from meshterm.tools.map import MapTool
from meshterm.ui.map_screen import _PAN_DIRS, _PAN_STEP
from meshterm.ui.map_screen import _TILE_RETRY_SECONDS as _TILE_RETRY
from meshterm.ui.mapcanvas import MapCanvas, parse_hex
from tests.conftest import plain as _plain # THE strip-and-join screen reader
if TYPE_CHECKING:
from meshterm.ui.map_screen import MapScreen
_FIXTURE = Path(__file__).parent / "fixtures" / "tile_14_4843_5861.mvt"
from tests.conftest import plain as _plain # THE strip-and-join screen reader
# -- MVT decoding -------------------------------------------------------------
+1 -1
View File
@@ -14,13 +14,13 @@ from meshterm.core.models import ChatMessage, utcnow
from meshterm.services.message_paths import Arrival
from meshterm.ui.message_paths_screen import MessagePathsScreen
from meshterm.ui.pathline import CRACK_HEAD, CRACK_TAIL
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _resolve(hop: str) -> str:
return {"3d63": "Hilltop-Repeater", "a1b2": "Waymarker"}.get(hop, hop)
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _screen(arrivals: list[Arrival], **kwargs) -> MessagePathsScreen:
+1 -1
View File
@@ -39,6 +39,7 @@ from meshterm.ui.pathgraph import DST_NODE, SRC_NODE
from meshterm.ui.pathline import CRACK_HEAD, CRACK_TAIL, SELF_GLYPH, PathHop, PathLine
from meshterm.ui.tui.screen import CANCEL, ListWindow
from meshterm.ui.widgets import highlighted_hash, route_graph_style, tab_strip
from tests.conftest import plain as _plain # THE strip-and-join screen reader
US = "aaaaaaaaaaaa"
HUB = Contact(name="Hub", public_key="3d63c6429436" + "0" * 52, key_prefix="3d63c6429436",
@@ -46,7 +47,6 @@ HUB = Contact(name="Hub", public_key="3d63c6429436" + "0" * 52, key_prefix="3d63
FAR = Contact(name="Far", public_key="f2c24f54551e" + "0" * 52, key_prefix="f2c24f54551e")
from tests.conftest import plain as _plain # THE strip-and-join screen reader
class _FakeSession:
+1 -1
View File
@@ -15,13 +15,13 @@ from meshterm.core.channels import channel_hash, derive_secret
from meshterm.core.models import utcnow
from meshterm.platforms import set_platform
from meshterm.ui.packet_viewer import PacketEntry, PacketViewer
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _stripped(lines: list[str]) -> list[str]:
return [re.sub(r"\x1b\[[0-9;]*m", "", line) for line in lines]
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _grp_txt_entry(raw_extra: dict) -> PacketEntry:
+1 -1
View File
@@ -30,6 +30,7 @@ from meshterm.ui.tui.screen import CANCEL
from meshterm.ui.tui.select import SelectScreen
from meshterm.ui.tui.session import TuiSession
from meshterm.ui.widgets import node_marker, self_marker
from tests.conftest import plain as _plain # THE strip-and-join screen reader
HUB_ID, FAR_ID = "3d63c6429436", "f2c24f54551e"
@@ -46,7 +47,6 @@ def _loop_shape() -> list[WalkVertex]:
]
from tests.conftest import plain as _plain # THE strip-and-join screen reader
def _resolve(hop: str) -> str:
+1 -1
View File
@@ -20,6 +20,7 @@ from meshterm.ui.pathline import (
)
from meshterm.ui.tui.render import render_to_ansi
from meshterm.ui.walk_screen import _HSCROLL_STEP, WalkScreen
from tests.conftest import plain as _plain # THE strip-and-join screen reader
US = "aa" * 6
Hub = Contact(name="Hilltop-Repeater", public_key="3d" * 32, node_type=2)
@@ -61,7 +62,6 @@ def _screen(topo: MeshTopology, cell_h: int = 24) -> WalkScreen:
return screen
from tests.conftest import plain as _plain # THE strip-and-join screen reader
# --- rendering ----------------------------------------------------------------------------