Skip to content

merge queue: checking main (7449e30) and #267 together - #270

Closed
mergify[bot] wants to merge 11 commits into
mainfrom
mergify/merge-queue/06db8a9e28
Closed

merge queue: checking main (7449e30) and #267 together#270
mergify[bot] wants to merge 11 commits into
mainfrom
mergify/merge-queue/06db8a9e28

Conversation

@mergify

@mergify mergify Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request has been checked successfully and will be merged soon. 🎉

Branch main (7449e30) and #267 are queued together for merge.

This pull request has been created by Mergify to check the mergeability of #267.
You don't need to do anything. Mergify will close this pull request automatically when it is complete.

Required conditions of queue rule default for merge:

Required conditions to stay in the queue:

---
checking_base_sha: 7449e3017200ec1b14448a21a241bcc5d9f8d37f
previous_check_retries: []
previous_failed_batches: []
pull_requests:
  - number: 267
    scopes: []
scopes: []
...

dependabot Bot and others added 11 commits August 9, 2026 16:04
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.22 to 0.16.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](astral-sh/ruff@0.15.22...0.16.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.16.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
ruff 0.16.0 expanded its default rule set from 59 rules to 413. This repo
never pinned `select`, so the bump inherited the whole new set at once and
`./doit.sh lint` reported 534 findings, failing CI.

This commit is pure tool output, so it can be skimmed rather than read:

    uv run ruff check --fix --unsafe-fixes --unfixable FLY002,UP031 .
    uv run ruff format $(git ls-files '*.py')
    ./doit.sh gen-docs

FLY002 and UP031 are held back because their fixes are worse than the
source. FLY002 collapses the CSP list in web/app.py into one 300-character
line and deletes the comments inside it. UP031 doubles every brace in the
eolymp GraphQL query. The next commit suppresses both at the site.

gen-docs runs here and not later: docs_test asserts docs/library.md matches
the generator, and the generator reads the signatures this commit rewrote.

44 findings remain, cleared by the commits that follow.
Moving `Callable`/`Awaitable` from `typing` to `collections.abc` (UP035, in
the previous commit) changed how they stringify: `typing.Callable` rendered
bare, but `collections.abc.Callable` carries its module prefix. That leaked
into docs/library.md, where `query_sync()` and `CrawlerInfo.query` grew
`collections.abc.` prefixes that tell a reader nothing.

_readable() already exists to drop such prefixes; give it the new module.
Records the five places the project declines a rule from ruff 0.16's new
413-rule default, so that nobody has to rediscover the reasoning:

- BLE001 is ignored project-wide. The catch-all `except Exception` is the
  crawler contract — any parse or transport failure becomes a RuntimeError
  the runner reports per crawler, so one judge's surprise never aborts a run.
- `fastapi.File` joins extend-immutable-calls. `File(...)` in a parameter
  default is how FastAPI declares an upload, not a B008 mistake.
- FLY002 is suppressed on the CSP in web/app.py. Its fix collapses the list
  into one 300-character line and deletes the comments inside it, and ADR
  0010 records that block as load-bearing.
- UP031 is suppressed on the eolymp GraphQL query. .format() needs every
  brace in the query body doubled.
- DTZ007 is suppressed on the chart date parse in web/pdf.py. Those keys are
  already local-day strings from compute_day_key(); the axis needs their
  order, not an instant.

ADR 0016 carries the argument for taking the new default set rather than
pinning `select = ["E4", "E7", "E9", "F"]`, and for reversing the typing
convention it collides with.

Findings drop from 44 to 16.
Ruff 0.16 formats Python blocks inside Markdown, which `ruff format .` now
reaches. Four files drifted. The result is worth keeping rather than
excluding: these blocks are templates that get copied into real .py files,
so matching the formatter is what a reader wants from them.

One block was edited by hand first. The standard-test-case list in the
crawlers skill puts one test per line, and the formatter would have exploded
the first line across three because its trailing comment pushed it past 88
characters. Dropping the redundant "raises" from two comments keeps the shape
and the exact match string.
run_crawler() and _async_main() timed their own work by subtracting two
datetime.now() readings. Wall-clock time is the wrong instrument for that: it
can be stepped by NTP or a timezone change mid-query, which yields a duration
that is too large, too small, or negative. time.monotonic() cannot run
backwards.

DTZ005 pointed at these four calls for the narrower reason that they carry no
timezone. Adding one would have silenced the rule while leaving the real
defect, so the clock changes instead.

The reported figure keeps its meaning and its format. Verified with a crawler
that sleeps 0.35s: run_crawler reports 0.352.
Both timestamps the app renders were naive, so they showed whatever zone the
server happened to run in and said nothing about which one that was. A reader
in Berlin saw a PDF stamped two hours behind their own clock with no way to
tell why.

The PDF footer now uses the reader's zone. PdfSnapshot.timezone already
carries it, and the day keys in the chart already respect it via
compute_day_key() — the footer was the one part of the report that ignored it.
The ZoneInfo lookup and its UTC fallback move into _resolve_tz() so both
callers share them.

/about has no reader zone available, because it is rendered server-side with
no JS, so its build time is explicit UTC and labelled as such.

Verified by rendering: Europe/Berlin gives "2026-08-11 17:39 CEST",
Asia/Shanghai "23:39 CST", an unknown zone falls back to "15:39 UTC", and
/about with BUILD_TIME set gives "2025-08-11 08:13:20 UTC".
The last ten findings, none of which ruff can fix safely:

- crawlers/__init__.py imported List and Union that nothing uses. The autofix
  rewrote the string annotation on query_sync() but left the import, because
  it cannot prove a string annotation is the only reference (F401, UP035).
- close_http_client() declared `global _CLIENT` but only reads it, so the
  statement did nothing (PLW0602). init_http_client() keeps its own, which
  does assign.
- Three tests asserted by evaluating a bare attribute inside pytest.raises.
  The access is the assertion, so binding the result to `_` keeps the intent
  and satisfies B018 without a suppression comment.
- Three temp PDFs used NamedTemporaryFile(delete=False), which SIM115 reads as
  a leaked handle. _write_temp_pdf() already existed for exactly this, so it
  now uses mkstemp with a context manager and the other two call sites route
  through it instead of repeating the pattern.

./doit.sh lint passes.
docs/dev/python.md told contributors the opposite of what the code now does:
"Use Dict, List, Union from the typing module". Ruff 0.16's defaults rewrite
exactly that, and the format-lint hook applies the rewrite on every edit, so
the old rule was both wrong and unenforceable.

Two sections change:

- Typing states the built-in generics and | unions, names the four rules that
  enforce it, and points at ADR 0016 for why it reversed.
- Import order was wrong independently of the bump. It read "standard library
  → third-party → typing", but typing and collections.abc *are* standard
  library and I001 sorts them into that first group.

The three query() templates in docs/dev/crawlers.md get the same treatment.
They are copied verbatim into new crawler files, so a stale template would
have reintroduced the old style on the next crawler.

Also records the eolymp GraphQL follow-up in docs/BACKLOG.md: passing the
username as a query variable would drop both the manual quote escaping and
the # noqa: UP031, but it changes the request payload and needs its own
network verification.
The lint task ran `ruff check` only, so `ruff format` drift never failed CI.
Ruff 0.16 made that gap visible: it formats python blocks inside markdown, and
four documentation files had drifted without any check noticing.

Both passes now run unconditionally rather than short-circuiting on the first
failure, so one `.doit/lint.log` lists every problem instead of hiding the
formatter behind the linter.

Verified by injecting a badly formatted line into a markdown code block: the
task exits 1 and the log shows the diff.
@mergify mergify Bot closed this Aug 11, 2026
@mergify
mergify Bot deleted the mergify/merge-queue/06db8a9e28 branch August 11, 2026 16:13
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