Skip to content

Add conjunctive signature constraints for slots #19

@pomponchik

Description

@pomponchik

pristan already supports an explicit expected call pattern for slots:

@slot(signature='..')
def on_event(event, context):
    ...

This is useful because plugin compatibility is checked against how the slot is expected to be called, not only against whether the slot and plugin have any common calling convention.

It would be useful to support two forms of signature:

@slot(signature='..')
def on_event(event, context):
    ...

@slot(signature=['..', '.'])
def on_event(event, context=None):
    ...

The list form should be interpreted as logical AND, not OR. In other words, both the slot itself and every plugin must satisfy every signature in the list.

This would allow a slot to declare several guaranteed call shapes when the host code intentionally calls it in more than one way. For example:

@slot(signature=['..', '.'])
def on_event(event, context=None) -> list[str]:
    ...

@on_event.plugin
def valid_plugin(event, context=None) -> str:
    return event.name

This plugin is valid because it can be called both with one positional argument and with two positional arguments.

Plugins that satisfy only one of the declared call shapes should fail immediately when registered:

@on_event.plugin
def invalid_plugin(event, context) -> str:
    return event.name

#> ...
#> sigmatch.errors.SignatureMismatchError: The signature of the callable object does not match the expected one.

invalid_plugin can be called as (event, context), but not as (event).

@on_event.plugin
def also_invalid_plugin(event) -> str:
    return event.name

#> ...
#> sigmatch.errors.SignatureMismatchError: The signature of the callable object does not match the expected one.

also_invalid_plugin can be called as (event), but not as (event, context).

The slot itself should also be checked against all declared signatures:

@slot(signature=['..', '.'])
def invalid_slot(event, context) -> list[str]:
    ...

#> ...
#> sigmatch.errors.SignatureMismatchError: The signature of the callable object does not match the expected one.

invalid_slot should be rejected for the same reason: it cannot satisfy the one-argument call shape.

This keeps the existing string API unchanged while making complex slot contracts explicit and checkable before runtime.

The exact implementation can vary. For example, the library could normalize signature into an internal sequence and run the existing matcher for every declared pattern, or it could introduce a dedicated matcher for conjunctive constraints. The important part is the public behavior: str remains a single expected signature, while list[str] means all listed signatures must match.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions