Skip to content

Migrate linting from flake8 to ruff - #5

Merged
martinhanzik merged 16 commits into
mainfrom
202606_messa_migrate_to_ruff
Jun 3, 2026
Merged

Migrate linting from flake8 to ruff#5
martinhanzik merged 16 commits into
mainfrom
202606_messa_migrate_to_ruff

Conversation

@messa

@messa messa commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces flake8 with ruff across all three components (agent, server, e2e_tests) and applies a few related code cleanups that the stricter linter surfaced.

Stacked on #3. The base of this PR is 202606_messa_update_to_uv, so the diff shows only the ruff changes. Merge #3 first, then this can be retargeted to main.

Changes

  • Migrate flake8 → ruff. Ruff config lives in each component's pyproject.toml: line length 150, rule sets E/F/W/I, and isort with force-sort-within-sections + two blank lines after the import block. The Makefiles and the GitHub Actions workflows now lint with uvx ruff check .. e2e_tests is now linted too (it previously had no lint step).
  • Fix the findings ruff surfaced: unused imports, != None / == Falseis not None / not ..., a redundant f-string prefix, an unused except ... as e, __all__ re-exports in the package __init__ modules, and a latent bug — an undefined name in the e2e rotate-log test's debug logging (this overlaps with Migrate to uv with per-component projects and Makefiles #3's own fix and merged cleanly).
  • Move imports to the top of each module. Hoist the lazy ssl / yaml / logging imports and switch hashlib usage to from hashlib import sha1. Conditional compatibility shims and optional-dependency fallbacks are intentionally left local.
  • Remove obsolete asyncio compatibility shims. With requires-python >= 3.9, asyncio.run / create_task / to_thread are always available, so asyncio_helpers.py is deleted and they are imported directly from asyncio.
  • Fix two latent deprecations: re.sub(..., re.ASCII) passed the flag as the positional count argument (now flags=re.ASCII); datetime.utcnow()datetime.now(timezone.utc).

Testing

make check is green for all three components: ruff clean, and 2 agent + 12 server + 7 e2e tests pass (including the real TLS round-trip).

🤖 Generated with Claude Code

messa and others added 13 commits June 2, 2026 13:09
Convert agent and server to standalone uv projects using the hatchling
build backend, with metadata moved from setup.cfg into pyproject.toml
([project] table) and committed uv.lock files. Remove setup.py/setup.cfg.

Add e2e_tests as a third uv project that pulls in agent and server via
editable path sources, and move its test modules into e2e_tests/tests/
to match the agent/server layout.

Add per-component Makefiles (check = lint + test) and make the root
Makefile delegate via $(MAKE) -C; add a server `image` target that builds
the container with podman and smoke-checks the entrypoint. Keep
run_e2e_tests as a backwards-compatible alias.

Rewrite the Dockerfile and the python-tests/e2e-tests workflows to use uv
(astral-sh/setup-uv, uv sync --frozen).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Bundle the MIT LICENSE into the agent and server wheels by symlinking
  the root LICENSE into each component (hatchling picks it up via PEP 639).
- server/Dockerfile: bump base image to python:3.14 and install
  dependencies in their own cached layer (uv sync --no-install-project)
  before copying the source, so source changes no longer invalidate the
  dependency install.
- CLAUDE.md: add an "Agent workflow" note to review changes via a
  background subagent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Martin Hanzík <martin@hanzik.com>
The debug log in test_rotate_log_file referenced expected_dst_second_file,
which is only defined in test_new_log_file_gets_copied. Use expected_dst_file
instead: the destination path actually in scope, and the same variable the
analogous first wait-loop already logs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a lint target to e2e_tests/Makefile, identical to the agent and server
ones, and make it part of the default check (check: lint test). Recurse into
e2e_tests from the root lint target so the aggregate lint now covers all
three components, matching the existing check and test aggregates.

Previously the e2e test code was the only Python in the repo not covered by
flake8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point the "project readme file" link at leadhub-code/logline instead of the
old messa/logline location, matching the homepage URLs already corrected in
the pyproject files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Switch both components from hatchling to uv's own uv_build backend:
- requires = ["uv_build>=0.11,<0.12"], build-backend = "uv_build"
- [tool.uv.build-backend] module-root = "" for the flat layout, since the
  package dir lives in the project root (not under src/) and uv_build
  defaults module-root to "src"
- license-files = ["LICENSE"] because uv_build, unlike hatchling, does not
  auto-glob license files

Replace the agent/server LICENSE symlinks with real copies of the repo-root
MIT license. uv_build validates license-files while building the project,
and the upward ../LICENSE symlink escaped the build root, which broke both
the server Docker build (context is server/) and isolated sdist builds.
Real copies fix every build path (wheel, sdist, Docker).

Copy LICENSE into the server image so uv_build's metadata validation passes
during uv sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace flake8 with ruff across all three components (agent, server,
e2e_tests). The ruff configuration lives in each component's
pyproject.toml: line length 150, rule sets E/F/W/I, and isort with two
blank lines after the import block. force-sort-within-sections keeps the
existing "sort by module name" import style, so reordering churn is small.

Update the Makefiles and GitHub Actions workflows to lint with
`uvx ruff check .`. The e2e_tests component is now linted as well
(previously it had no lint step), which surfaced a latent bug: a debug
log in test_rotate_log_file referenced an undefined name
(expected_dst_second_file instead of expected_dst_file).

Apply ruff's autofixes (import sorting, unused imports, redundant f-string
prefix, unused exception variable) and fix the remaining findings by hand:
- re-export the entry points via __all__ in the package __init__ modules
- reference the imported module in the smoke tests
- use `is not None` / `not ...` instead of `!= None` / `== False`
- fix the undefined name in the e2e rotate test

Document the Python style conventions (line length, two blank lines after
imports, preferring `from X import Y`) in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hoist function-local imports to module level where there is no reason to
defer them:
- logging name imports in setup_logging/setup_log_file (agent and server)
- the logging import in the e2e conftest
- the lazy ssl imports in the TLS branches (agent client, server)
- the lazy yaml imports in the configuration loaders (agent and server)

Also switch hashlib usage to `from hashlib import sha1` to match the
`from X import Y` convention.

Conditional compatibility shims (try/except ImportError in asyncio_helpers
and util), the optional zstandard/zstd fallbacks, and the smoke-test
imports are intentionally left local.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The minimum supported Python version is 3.9, where asyncio.run,
asyncio.create_task and asyncio.get_running_loop (all 3.7+) and
asyncio.to_thread (3.9+) are always available, so the fallback shims are
dead code.

Delete the agent's asyncio_helpers module and import run/create_task/
to_thread directly from asyncio. Drop the to_thread shim from the
server's util module the same way.

The zstandard/zstd fallback in util is intentionally kept: it selects
between two optional libraries at runtime and is not a Python-version shim.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In the agent's obfuscate_secrets(), re.ASCII was passed as the 4th
positional argument to re.sub(), which is `count`, not `flags`. That made
the flag a no-op (256 used as the replacement count) and triggered a
DeprecationWarning on Python 3.13+. Pass it as `flags=re.ASCII`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
datetime.utcnow() returns a naive datetime and is deprecated since Python
3.12. Use datetime.now(timezone.utc) instead. The rendered string is
unchanged: the strftime format ('%Y%m%dT%H%M%SZ') has no %z/%Z field and
the trailing Z is a literal, so the rotated-file suffix stays identical.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 14:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates Python linting across the repo from flake8 to ruff (agent/server/e2e_tests), updates CI/Makefiles accordingly, and applies small code cleanups and compatibility-shim removals to satisfy the stricter linter and the project’s requires-python >= 3.9.

Changes:

  • Replace flake8 with ruff: add per-component Ruff configuration in pyproject.toml, and switch make lint + GitHub Actions lint steps to uvx ruff check ..
  • Remove obsolete asyncio compatibility shims (e.g., asyncio_helpers.py) and import run/create_task/to_thread directly from asyncio.
  • Apply Ruff-driven cleanups (import ordering, is not None / not ..., fix re.sub(..., flags=...), and datetime.now(timezone.utc)).

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated no comments.

Show a summary per file
File Description
server/tests/test_smoke.py Ensure the import is “used” to satisfy unused-import linting.
server/tests/test_destination_path.py Import ordering cleanup consistent with Ruff/isort rules.
server/pyproject.toml Add Ruff configuration (line length + E/F/W/I + isort settings).
server/Makefile Switch lint target to uvx ruff check ..
server/logline_server/util.py Remove legacy to_thread polyfill; rely on stdlib asyncio.to_thread.
server/logline_server/main.py Import hoisting/cleanup; utcnow() deprecation fix; != Noneis not None; SHA1 import style change.
server/logline_server/configuration.py Hoist yaml import to module scope.
server/logline_server/__main__.py Add spacing to satisfy import-block formatting.
server/logline_server/__init__.py Add __all__ export and spacing per import-block formatting.
e2e_tests/tests/test_tls.py Import cleanups and SHA1 import style change.
e2e_tests/tests/test_e2e.py Import cleanups; boolean assertion simplification.
e2e_tests/tests/conftest.py Hoist logging imports to module scope.
e2e_tests/pyproject.toml Add Ruff configuration for the e2e project.
e2e_tests/Makefile Switch lint target to uvx ruff check ..
CLAUDE.md Document Ruff-based Python style/linting workflow and conventions.
agent/tests/test_smoke.py Ensure the import is “used” to satisfy unused-import linting.
agent/tests/test_main.py Import ordering cleanup consistent with Ruff/isort rules.
agent/tests/conftest.py Add spacing per import-block formatting.
agent/pyproject.toml Add Ruff configuration (line length + E/F/W/I + isort settings).
agent/Makefile Switch lint target to uvx ruff check ..
agent/logline_agent/main.py Remove asyncio helper imports and hoist logging imports.
agent/logline_agent/configuration.py Hoist yaml import to module scope.
agent/logline_agent/client.py Use stdlib asyncio.to_thread; fix re.sub flags argument; import cleanups.
agent/logline_agent/asyncio_helpers.py Delete obsolete asyncio compatibility shim module.
agent/logline_agent/__main__.py Add spacing to satisfy import-block formatting.
agent/logline_agent/__init__.py Add __all__ export and spacing per import-block formatting.
.github/workflows/python-tests.yml Switch lint steps from flake8 to ruff for agent/server jobs.
.github/workflows/e2e-tests.yml Add Ruff lint step for e2e tests workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@messa
messa requested a review from martinhanzik June 2, 2026 15:03
@messa messa self-assigned this Jun 2, 2026
@messa

messa commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Why there are no checks running?

Copilot AI commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

@copilot Why there are no checks running?

Because all CI workflows are configured to run only when the PR base branch is main (pull_request.branches: [ main ] in .github/workflows/*). This stacked PR targets 202606_messa_update_to_uv, so those workflows are skipped, and only dynamic Copilot workflows run. The checks did run on the base branch PR targeting main.

Copilot finished work on behalf of messa June 2, 2026 15:12
Drop the `branches: [ main ]` filter from the pull_request trigger in all
workflows so that PRs targeting a feature branch (e.g. stacked PRs) also
get CI. The push trigger stays restricted to main, so feature-branch
pushes don't produce a second, redundant run. Also drop the now-inaccurate
"must be a subset" comment in the CodeQL workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Base automatically changed from 202606_messa_update_to_uv to main June 3, 2026 12:51
@martinhanzik
martinhanzik merged commit 03b9c79 into main Jun 3, 2026
20 checks passed
@martinhanzik
martinhanzik deleted the 202606_messa_migrate_to_ruff branch June 3, 2026 12:58
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.

4 participants