Skip to content

Commit 63d933e

Browse files
committed
Enforce best practices concerning annotations, typing and symbol import/export
1 parent fb20014 commit 63d933e

13 files changed

Lines changed: 371 additions & 264 deletions

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,34 @@ on:
1010
- "docs/**"
1111
- ".readthedocs.yaml"
1212
- "pyproject.toml"
13-
- "setup.cfg"
13+
- "mypy.ini"
1414
- "**/*.py"
1515
pull_request:
1616
paths:
1717
- ".github/workflows/type-checking.yml"
1818
- "docs/**"
1919
- ".readthedocs.yaml"
2020
- "pyproject.toml"
21-
- "setup.cfg"
21+
- "mypy.ini"
2222
- "**/*.py"
2323

24+
concurrency:
25+
# Cancel previous runs for the same PR
26+
# Don't cancel successive pushes to master
27+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
28+
cancel-in-progress: true
29+
2430
jobs:
31+
ruff:
32+
runs-on: ubuntu-latest
33+
timeout-minutes: &timeout-minutes 5
34+
steps:
35+
- uses: actions/checkout@v6
36+
- uses: astral-sh/ruff-action@v4.0.0
37+
2538
mypy:
2639
runs-on: ${{ matrix.os }}
40+
timeout-minutes: *timeout-minutes
2741
strategy:
2842
matrix:
2943
os: [windows-latest, ubuntu-latest, macos-latest]
@@ -39,6 +53,7 @@ jobs:
3953

4054
sphinx:
4155
runs-on: ubuntu-22.04 # Keep in sync with build.os in .readthedocs.yaml
56+
timeout-minutes: *timeout-minutes
4257
steps:
4358
- uses: actions/checkout@v4
4459
- uses: actions/setup-python@v6

mypy.ini

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[mypy]
2+
python_version = 3.9
3+
mypy_path = src/, typings/
4+
exclude = build
5+
strict = True
6+
7+
# Leverage type inference for function return type
8+
disallow_untyped_calls = False
9+
disallow_incomplete_defs = False
10+
disallow_untyped_defs = False
11+
12+
disable_error_code =
13+
# https://github.com/python/mypy/issues/6232 (redefinition with correct type)
14+
attr-defined, assignment,

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ dev = [
6969
{include-group = "docs"},
7070
"ewmhlib",
7171
"mypy>=0.990,<2",
72+
"ruff>=0.15.17",
7273
"types-python-xlib>=0.32",
7374
"types-pywin32>=305.0.0.3",
7475
"types-setuptools>=65.5",

ruff.toml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
[lint]
2+
future-annotations = true
3+
# https://docs.astral.sh/ruff/rules/
4+
extend-select = [
5+
"ANN2", # flake8-annotations: missing-return-type
6+
"PYI", # flake8-pyi
7+
"FA", # flake8-future-annotations
8+
"ICN", # flake8-import-conventions
9+
"F401", # unused-import
10+
"YTT", # flake8-2020
11+
"TC", # flake8-type-checking
12+
"TID", # flake8-tidy-imports
13+
"UP", # pyupgrade
14+
"RUF", # Ruff-specific rules
15+
"F404", # late-future-import
16+
"PGH", # pygrep-hooks (blanket-* rules)
17+
]
18+
ignore = [
19+
# Only enforce return types on public functions. Where otherwise mypy infers as Any
20+
# Still worth running `ruff check --fix --select=202` once in a while for autofixes
21+
"ANN202", # missing-return-type-private-function
22+
# Explicit is preferred
23+
"UP015", # redundant-open-modes,
24+
# Autofixes print-f style formatting to f-strings,
25+
# which is sometimes simpler, but looses template code reading semantics
26+
"UP032", # f-string
27+
# TC helps prevent circular imports, reduce runtime cost of typing symbols,
28+
# and prevent leaking implementations details into modules
29+
# However stdlib is not at risk of circular import, is clearly not public API,
30+
# and assume it's gonna be included in the import chain at some point anyway
31+
"TC003", # typing-only-standard-library-import
32+
# Typeshed doesn't want complex or non-literal defaults for maintenance and testing reasons.
33+
# This doesn't affect us, let's have more complete stubs.
34+
"PYI011", # typed-argument-default-in-stub
35+
"PYI014", # argument-default-in-stub
36+
"PYI053", # string-or-bytes-too-long
37+
38+
# TODO: Consider later
39+
"UP031", # printf-string-formatting
40+
"RUF059", # unused-unpacked-variable
41+
"E722", # bare-except
42+
]
43+
# F401 would remove imports not marked as explicit re-exports, which may break API boundaries
44+
extend-unsafe-fixes = ["F401"]
45+
46+
[lint.per-file-ignores]
47+
"**/typings/**/*.pyi" = [
48+
"PGH003", # TODO: Blanket ignores until using pyobj type stubs
49+
"F811", # Re-exports false positives
50+
# The following can't be controlled for external libraries:
51+
"A", # Shadowing builtin names
52+
"E741", # ambiguous variable name
53+
"F403", # `from . import *` used; unable to detect undefined names
54+
"FBT", # flake8-boolean-trap
55+
"ICN001", # unconventional-import-alias
56+
"N8", # Naming conventions
57+
"PLC2701", # Private name import
58+
"PLE0302", # The special method expects a given signature
59+
"PLR0904", # Too many public methods
60+
"PLR0913", # Argument count
61+
"PLR0917", # Too many positional arguments
62+
"PLW3201", # misspelled dunder method name
63+
"SLOT", # flake8-slots
64+
# Stubs can sometimes re-export entire modules.
65+
# Issues with using a star-imported name will be caught by type-checkers.
66+
"F405", # may be undefined, or defined from star imports
67+
# It's normal to be missing annotations for local stubs.
68+
# If they were complete, we'd upload them to typeshed!
69+
"ANN0",
70+
"ANN2",
71+
]

setup.cfg

Lines changed: 0 additions & 23 deletions
This file was deleted.

setup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import io
21
import os
32
import re
43

@@ -17,7 +16,7 @@
1716
version = match.group(1)
1817

1918
# Use the README.md content for the long description:
20-
with io.open("README.md", encoding="utf-8") as fileObj:
19+
with open("README.md", encoding="utf-8") as fileObj:
2120
long_description = fileObj.read()
2221

2322

src/pywinctl/__init__.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
#!/usr/bin/python
2-
# -*- coding: utf-8 -*-
2+
from ._main import (Re, Window, checkPermissions, getActiveWindow,
3+
getActiveWindowTitle, getAllAppsNames, getAllAppsWindowsTitles,
4+
getAllTitles, getAllWindows, getAppsWithName, getWindowsWithTitle,
5+
getAllWindowsDict, getTopWindowAt, getWindowsAt, displayWindowsUnderMouse,
6+
getAllScreens, getScreenSize, getWorkArea, getMousePos
7+
)
38

4-
__all__ = [
9+
__all__ = [ # noqa: RUF022
510
"version", "Re",
611
# OS Specifics
712
"Window", "checkPermissions", "getActiveWindow", "getActiveWindowTitle", "getWindowsWithTitle",
@@ -18,9 +23,3 @@ def version(numberOnly: bool = True) -> str:
1823
return ("" if numberOnly else "PyWinCtl-")+__version__
1924

2025

21-
from ._main import (Re, Window, checkPermissions, getActiveWindow,
22-
getActiveWindowTitle, getAllAppsNames, getAllAppsWindowsTitles,
23-
getAllTitles, getAllWindows, getAppsWithName, getWindowsWithTitle,
24-
getAllWindowsDict, getTopWindowAt, getWindowsAt, displayWindowsUnderMouse,
25-
getAllScreens, getScreenSize, getWorkArea, getMousePos
26-
)

0 commit comments

Comments
 (0)