Skip to content

refactor: modernize the project layout and tooling - #4

Merged
WigoWigo10 merged 7 commits into
chore/fork-identity-and-hygienefrom
refactor/modernize-project-layout
Aug 1, 2026
Merged

refactor: modernize the project layout and tooling#4
WigoWigo10 merged 7 commits into
chore/fork-identity-and-hygienefrom
refactor/modernize-project-layout

Conversation

@WigoWigo10

Copy link
Copy Markdown
Owner

No description provided.

WigoWigo10 and others added 7 commits July 31, 2026 22:39
With the package at the repository root, `import directkeys` from the checkout
directory picks up the source tree rather than the installed distribution.
That hides packaging mistakes: a module missing from the wheel still imports
fine locally and only fails for users. Moving to src/ makes the test run
exercise the installed package.

Also folds .coveragerc into pyproject.toml and configures pytest there, so
`testpaths` and the tests/manual exclusion no longer have to be repeated on
every invocation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Python 3.8 reached end of life in October 2024 and no longer receives security
fixes, so requires-python moves to 3.9 and the CI matrix follows (3.9, 3.11,
3.13 on Windows and Linux). This also removes the need to pin an older Ubuntu
runner, since 3.8 is the version ubuntu-latest stopped shipping.

With Python 2 long out of scope, the compatibility layer was dead weight that
made every module harder to read:

- Remove the `basestring` / `unichr` / `long` fallbacks and the
  `from __future__` imports, using `str`, `chr` and `int` directly.
- Remove the `time.monotonic` fallback, present on every supported version.
- Replace the Python2 `Queue` / `threading._Event` branch with a plain import.
- Turn the `_is_str` / `_is_number` / `_is_list` lambdas into functions and drop
  the redundant `(object)` base classes and UTF-8 coding cookies.
- Restore two upstream comments explaining `_State` and the `_Event.wait`
  override, lost when the compatibility block was edited.

Also introduces `__version__` as the canonical attribute, keeping `version` as
an alias so code reading `keyboard.version` keeps working. The setuptools
dynamic version now points at `__version__`, which is a literal and can be read
statically; the alias is not, and would have forced an import at build time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds Ruff (lint + import sorting) configured in pyproject.toml, targeting
py39. Rules that the codebase deliberately breaks are ignored explicitly, each
with the reason, rather than left to fail: long lines in the ctypes tables,
imports that must follow the platform dispatch, and the Cyrillic/Greek key
names in _canonical_names.py that RUF001 reads as ambiguous characters.

The autofixable findings are applied. Two are worth calling out:

- tests/test_keyboard.py defined four tests twice under the same name, so the
  first definition of each was silently discarded and never ran. They are not
  duplicates, they are distinct cases: a `write` without delay, a hotkey
  removal without modifiers, a two-modifier release, and a multistep blocking
  state assertion. Renamed so both run; the suite goes from 157 to 161 tests
  and all four recovered cases pass.
- `index = 0` in the suppression path assigned to a local that nothing read,
  right before `set_index(0)` did the real work.

A group of upstream findings is ignored rather than fixed, because each would
change runtime behaviour and none is covered by a test: repeated dictionary
keys (F601), mutable argument defaults (B006), bare except (E722) and
`raise` without `from` (B904).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mechanical reformat of every Python file, in its own commit so the substantive
changes elsewhere stay reviewable.

Two settings needed care:

- `docstring-code-format` is left off. The __init__ docstring is published
  verbatim as the PyPI description and regenerated into README.md, so the
  formatter must not rewrite the example code inside it.
- Markdown is excluded. Ruff reformats fenced Python blocks in .md files, and
  since README.md is generated from that same docstring, the formatter and the
  generator would each keep undoing the other.

Verified by comparing the AST of every touched file before and after: 17 are
byte-identical, and the remaining 8 differ only in whitespace inside string
literals, where Ruff normalises `""" Text. """` to `"""Text."""`. No
structural change in any file. README.md is regenerated so it stays in sync
with the docstring after that normalisation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rounds out the tooling so the checks that CI runs can also run locally before
a commit, and so contributors get consistent whitespace regardless of editor.

- .pre-commit-config.yaml runs Ruff (check + format) plus the standard
  whitespace and syntax hooks. README.md is excluded from the whitespace hooks
  because it is generated from the module docstring.
- The `mixed-line-ending` hook is deliberately left out: `.gitattributes`
  already normalises endings at the git level, and forcing LF in the working
  tree would fight the CRLF checkout on Windows in a loop.
- .editorconfig mirrors the same rules for editors.
- Dependabot keeps the Actions and pip pins current, monthly.
- A `lint` job runs Ruff in CI.

.gitattributes drops the Visual Studio and msysgit boilerplate inherited from
the original template, keeps the `text=auto` normalisation, and marks README.md
as generated so it stops inflating pull request diffs.

Verified by running `pre-commit run --all-files` twice: the second run is clean,
so the hooks are idempotent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Records the modernisation in CHANGES.md, including the Python 3.9 requirement,
the src/ layout and the tooling, alongside the fixes made earlier on the fork.

The module docstring gains a Development section covering the editable install,
pre-commit and the two Ruff checks CI runs, and states the supported Python
version where the removed "Python 2 and 3" line used to be. README.md is
regenerated from it.

Also widens the margin in test_record. The test races a background thread that
has to register both the recording hook and the suppressing hotkey before the
events are fed in, and upstream already noted the 0.01s sleep had lost that
race once; it lost it again here. There is no public barrier to synchronise on,
so this is a larger margin rather than a real fix, and the comment says so.
Ten consecutive full runs pass afterwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@WigoWigo10
WigoWigo10 merged commit c9bd7a5 into chore/fork-identity-and-hygiene Aug 1, 2026
8 checks passed
@WigoWigo10
WigoWigo10 deleted the refactor/modernize-project-layout branch August 1, 2026 23:00
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