Declare accepted indicator types on process(), not in defaults.py - #289
Merged
Conversation
Collaborator
Author
|
Merge order — blocked on #290. The failing This PR touches only Merge path: merge #290 first, then this branch gets rebased on |
The indicator-type filter that routes a shared bind like @IOC lived in an ACCEPTS list in each module's defaults.py -- a separate declaration that could silently drift from what the command's process() actually looks up. Move the contract onto the handler itself with a @cmdutils.handles(...) decorator, so the accepted types sit next to the code that consumes them and cannot fall out of sync. (Idea from TTycho's typing-for-modules branch, which puts accepted types on the function signature; adapted to our stdlib-only classifier and our fixed process() signature, where params also carries non-indicator options so a bare type annotation would misrepresent it.) - cmdutils.handles(*types): attaches the declared types to process(); the loader reads that attribute through normalise_accepts into the command entry the dispatcher already gates on. No decorator -> accept-anything, unchanged. - matterbot.py: read the decorator off process() instead of defaults.ACCEPTS (and drop the settings.py ACCEPTS override -- the type a module handles is a code fact, not deployment config). - Migrate all 16 annotated modules; relocate the substantive per-module WHY (netblock endpoint, IPv4-only, URL scheme gate) next to the decorator. - Tests read the decorator via AST (dependency-free) instead of defaults.ACCEPTS, so the shipped-invariant checks still catch a bad edit to a real module.
spierenburg
force-pushed
the
feat/accepts-on-handler
branch
from
July 26, 2026 12:31
10f3e4f to
6633e62
Compare
spierenburg
added a commit
that referenced
this pull request
Aug 4, 2026
Following #289, the opt-in is declared with @cmdutils.aitool on process() rather than AITOOL in defaults.py, so the README, the AI: config block and the _registry() comment all still described the old shape. Also states the property the move buys, which the old prose did not: the decorator cannot be set from defaults.py/settings.py, so the config lists can only ever subtract from the exposed set -- they cannot widen it past what a developer marked safe.
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.
What
The indicator-type filter that routes a shared bind like
@ioclived in anACCEPTSlist in each module'sdefaults.py— a declaration separate from theprocess()that actually consumes those types, so the two could silently drift.This moves the contract onto the handler with a
@cmdutils.handles(...)decorator, so the accepted types sit next to the code that looks them up and can't fall out of sync.Honorable mention
The idea comes from @TTycho's
typing-for-modulesbranch, which declares each command's accepted types directly on the function signature (def search(parameters: list[ASN], ...)) rather than in a side table. Credit to him for the core insight — the type contract belongs on the handler. This PR adapts it to our current architecture rather than porting it wholesale:process(command, channel, username, params, files, conn)signature hasparamsalso carrying non-indicator options (abuseipdb's max-age, hibp's search-type), so a bareparams: list[IP]hint would misrepresent it — and restructuring the universal signature across ~40 modules is riskier than the drift it fixes.cmdutils.classify()classifier so the dependency-freepython -m unittestrunner still works (his branch pulls invalidators+tldextract).Changes
cmdutils.handles(*types)attaches the declared types toprocess(); the loader reads that attribute throughnormalise_acceptsinto the command entry the dispatcher already gates on. No decorator → accept-anything, unchanged and backwards-compatible.matterbot.py: read the decorator offprocess()instead ofdefaults.ACCEPTS, and drop thesettings.pyACCEPTS override — what indicator types a module's code handles is a code fact, not deployment config.defaults.ACCEPTSread breaks any un-migrated one). Relocated the substantive per-module WHY (netblock endpoint, IPv4-only, URL scheme gate) next to the decorator; dropped generic boilerplate.defaults.ACCEPTS, so the shipped-invariant checks still catch a bad edit to a real module.Testing
python -m unittest tests.test_cmdutils→ 39/39 pass (3 new decorator tests + the 16-module routing-invariant checks that read the real decorators).