Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,16 @@ concurrency:
cancel-in-progress: true

jobs:
ruff:
runs-on: ubuntu-latest
timeout-minutes: &timeout-minutes 5
steps:
- uses: actions/checkout@v6
- uses: astral-sh/ruff-action@v4.0.0

mypy:
runs-on: ${{ matrix.os }}
timeout-minutes: &timeout-minutes 5
timeout-minutes: *timeout-minutes
strategy:
# mypy is os and python-version sensitive. Test on all supported combinations
matrix:
Expand All @@ -42,3 +49,52 @@ jobs:
activate-environment: true
- run: uv sync --locked
- run: mypy . --python-version=${{ matrix.python-version }}

tests:
runs-on: ${{ matrix.os }}
timeout-minutes: *timeout-minutes
strategy:
# Test on all supported runtime combinations
matrix:
# Arm runners are faster (as long as the same wheels are available)
# This project doesn't have any code that should act differently per architecture
os: [windows-11-arm, ubuntu-24.04-arm, macos-latest]
# TODO: Run tests in parallel on free-threaded python to catch free-threading issues
# See: https://py-free-threading.github.io/testing/
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
fail-fast: false
steps:
- uses: actions/checkout@v6
- name: Install Linux Packages
if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: |
# xvfb+openbox: headless X server and WM
# x11-xserver-utils (xrandr/xset): required by tests for window geometry
sudo apt install -y xvfb openbox x11-xserver-utils
- uses: astral-sh/setup-uv@v8.2.0
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
- run: uv sync --locked
- name: Run tests (Linux)
if: ${{ startsWith(matrix.os, 'ubuntu') }}
working-directory: tests
run: xvfb-run --server-args="-screen 0 1280x1024x24" bash -c "openbox & sleep 1 && python test_pymonctl.py"
- name: Run tests (Windows & macOS)
if: ${{ !startsWith(matrix.os, 'ubuntu') }}
working-directory: tests
run: python test_pymonctl.py

sphinx:
runs-on: ubuntu-24.04-arm # Keep in sync with build.os in .readthedocs.yaml
timeout-minutes: *timeout-minutes
steps:
- uses: actions/checkout@v6
- uses: astral-sh/setup-uv@v8.2.0
with:
python-version: "3.14" # Keep in sync with build.tools.python in .readthedocs.yaml
activate-environment: true
- run: uv sync --locked --no-default-groups --group=docs
- name: Build docs
# TODO: Add --fail-on-warning, but still too many warnings right now
run: sphinx-build --keep-going --builder html docs/source docs/_build/html
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ dependencies = [
docs = ["myst-parser"]
dev = [
{ include-group = "docs" },
"ruff>=0.15.16",
"ewmhlib",
"mypy>=0.990,<2",
"types-python-xlib>=0.32",
Expand Down
95 changes: 95 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
[lint]
future-annotations = true
# https://docs.astral.sh/ruff/rules/
extend-select = [
"ANN2", # flake8-annotations: missing-return-type
"C4", # flake8-comprehensions
"F401", # unused-import
"F404", # late-future-import
"FA", # flake8-future-annotations
"FLY", # Flynt
"ICN", # flake8-import-conventions
"PERF", # Perflint
"PGH", # pygrep-hooks (blanket-* rules)
"PYI", # flake8-pyi
"RUF", # Ruff-specific rules
"SIM9", # flake8-simplify: split-static-string + zip-dict-keys-and-values
"SLOT", # flake8-slots
"TC", # flake8-type-checking
"TID", # flake8-tidy-imports
"UP", # pyupgrade
"YTT", # flake8-2020
]
ignore = [
# Only enforce return types on public functions. Where otherwise mypy infers as Any
# Still worth running `ruff check --fix --select=202` once in a while for autofixes
"ANN202", # missing-return-type-private-function
# Explicit is preferred
"UP015", # redundant-open-modes,
# Autofixes print-f style formatting to f-strings,
# which is sometimes simpler, but looses template code reading semantics
"UP032", # f-string
# TC helps prevent circular imports, reduce runtime cost of typing symbols,
# and prevent leaking implementations details into modules
# However stdlib is not at risk of circular import, is clearly not public API,
# and assume it's gonna be included in the import chain at some point anyway
"TC003", # typing-only-standard-library-import
# Typeshed doesn't want complex or non-literal defaults for maintenance and testing reasons.
# This doesn't affect us, let's have more complete stubs.
"PYI011", # typed-argument-default-in-stub
"PYI014", # argument-default-in-stub
"PYI053", # string-or-bytes-too-long
# Good to watch for, but often unfixable
# Anyway Python 3.11 introduced "zero cost" exception handling
"PERF203", # try-except-in-loop,

# TODO: Add and configure isort (I) first
"RUF022",

# TODO: Consider later
"UP031", # printf-string-formatting
"RUF059", # unused-unpacked-variable

# TODO: Not autofixable, address in a separate PR !
"E402",
"E722",
"F401",
"PERF401",
"PYI063",
"RUF003",
"RUF012",
"RUF022",
]
# F401 would remove imports not marked as explicit re-exports, which may break API boundaries
extend-unsafe-fixes = ["F401"]

[lint.per-file-ignores]
"**/typings/**/*.pyi" = [
"E402", # https://github.com/astral-sh/ruff/issues/26160
"F811", # Re-exports false positives
# The following can't be controlled for external libraries:
"A", # Shadowing builtin names
"E741", # ambiguous variable name
"F403", # `from . import *` used; unable to detect undefined names
"FBT", # flake8-boolean-trap
"ICN001", # unconventional-import-alias
"N8", # Naming conventions
"PLC2701", # Private name import
"PLE0302", # The special method expects a given signature
"PLR0904", # Too many public methods
"PLR0913", # Argument count
"PLR0917", # Too many positional arguments
"PLW3201", # misspelled dunder method name
"SLOT", # flake8-slots
# Stubs can sometimes re-export entire modules.
# Issues with using a star-imported name will be caught by type-checkers.
"F405", # may be undefined, or defined from star imports
# It's normal to be missing annotations for local stubs.
# If they were complete, we'd upload them to typeshed!
"ANN0",
"ANN2",
]

# https://docs.astral.sh/ruff/settings/#lintflake8-type-checking
[lint.flake8-type-checking]
quote-annotations = true
1 change: 0 additions & 1 deletion src/pymonctl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from importlib.metadata import version as _importlib_version

__all__ = [
Expand Down
Loading
Loading