chore: land the fork identity and project modernization on master - #5
Merged
Conversation
setup.py publishes `directkeys.__doc__` as the PyPI long_description, and the Makefile regenerates README.md from that same docstring — so the docstring was the single source still advertising the upstream project. It told readers to `pip install keyboard`, pointed every link at boppreh/keyboard, and the README carried the upstream "this project is currently unmaintained" banner, which is the opposite of this fork's premise. - Retitle to directkeys and state up front that this is a maintained fork. - Point install/clone/API links at this repository. - Add a "New in this fork" section and a migration note for `import keyboard`. - Drop the "Python 2 and 3" claim, which contradicts the 3.8+ classifiers. - Rewrite the generated [source] links to this repo and the directkeys package. References to boppreh/mouse and to upstream issues boppreh#20/boppreh#21/boppreh#22 are left alone: they point at a sibling project and at real upstream discussions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ackend
The backend still carried editing instructions left over from when the AltGr
support was pasted in ("COLE ESTAS DUAS FUNCOES DEPOIS DE...", "O resto do
arquivo continua aqui...", "Esta funcao voce ja deve ter no final do
arquivo"), which read as documentation to anyone else opening the file.
Alongside that:
- Remove `_remove_alt_gr_mapping`, which was never called.
- Remove `shift_is_pressed` and `shift_vks`: the global was still being
assigned on every shift event but nothing read it, since `get_modifiers`
queries GetKeyState directly. Same for `ignore_next_right_alt`, only ever
reset and never read.
- Guard the `to_name` mutation in `get_name` with `tables_lock`, matching every
other access to the tables. This also serialises the shared ctypes buffers
used by `get_event_names`.
- Fold the duplicated modifier vk lists in `force_reset_keyboard` and
`get_stuck_keys` into a single `_modifier_vk_names` mapping.
- Restore the two upstream comments explaining the `fake_alt` / VK_PACKET
guard, and move the `__main__` block back to the end of the file.
- Translate the new comments and docstrings to English, matching the rest of
the codebase and the published API docs.
No behaviour change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`set_alt_gr_abstraction`, `get_alt_gr_abstraction_state` and the fallback helpers are part of the published API: docstring2markdown renders them into README.md and setup.py ships the module docstring as the PyPI description, so they were the only Portuguese text in the user-facing documentation. Also correct the feature list: `KeyboardEvent.flags` is masked down to the LLKHF_EXTENDED bit on Windows, so describing it as the raw hook flags overstated what the attribute actually carries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
setup.py imported the package at build time to read the version and the docstring, which meant a build could fail before install_requires had a chance to provide pyobjc on macOS. Move all metadata to pyproject.toml and reduce setup.py to a shim so legacy invocations keep working. - Read the version statically via `[tool.setuptools.dynamic]`, keeping `directkeys.version` as the single source of truth without importing it. - Take long_description from README.md, which the Makefile already generates from the module docstring. - Declare requires-python >=3.8 to match the classifiers, add 3.13, and use the more specific "POSIX :: Linux" operating system classifier. - Point the Makefile at `python -m build`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CHANGES.md still started at 0.13.5, so the release that renamed the package and added the AltGr, stuck key and flags features had no entry at all. LICENSE.txt keeps the original BoppreH copyright, as the MIT terms require, with the fork's copyright added alongside it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
run_test.py and run_test_2a_crash.py sat at the repository root, where they read like the project's test entry point despite being interactive scripts that block on a human pressing keys on a physical keyboard. Neither keeps a `test_` prefix, so pytest cannot collect them: as test functions their `read_event()` calls would hang the suite waiting for input. The helper script is now resolved relative to __file__ rather than the current working directory, and a module docstring states what the scripts need to run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The repository had no CI at all, which is an awkward gap for a fork whose pitch is that it is the maintained one. Adds a workflow that runs the suite on Windows and Linux across the Python versions declared in requires-python, plus a job that builds the distribution and runs `twine check` on it. tests/manual is excluded: those scripts need a physical keyboard and a human. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PRs #3 and #4 were merged into their intermediate branches rather than into
master, which is the expected behaviour for a stacked series merged top-down.The result is that
mastercurrently carries only the four fixes from #2 andhas neither
pyproject.tomlnor thesrc/layout.This PR brings the tip of the stack straight to
master. The four commits from#2 are common ancestors, so the diff is exactly the 14 commits that never
landed, with no duplication.
What lands here
Fork identity (was #3)
unmaintained" banner, and the module docstring — which setup.py publishes as
the PyPI description — still told readers to
pip install keyboard.pyproject.toml, 1.0.0 changelog entry, forkcopyright alongside the original, CI, and the interactive scripts moved out
of the repository root into
tests/manual/.Modernization (was #4)
src/layout, so the test run exercises the installed distribution.build +
twine check.Verification
twine checkpasses and thefork's APIs work from the installed package.
before and after: 17 byte-identical, 8 differing only in docstring
whitespace, 0 structural changes.
test_keyboard.pydefined four tests twice under the same name, so the first of each pair was
silently discarded and never ran.
Known issues, not addressed here
_darwinmouse.pycalls four names that do not exist in the module, so mouselistening on macOS raises
NameError. Inherited from upstream; fixing itneeds a macOS machine to verify against.
test_recordis timing-dependent and flaky. The margin was widened and thecomment says it is a mitigation, not a fix.
is the first time they execute on GitHub Actions.
🤖 Generated with Claude Code