correspond.routing#
Deciding what a message is about: a transparent rule chain.
The rules belong to the caller; correspond runs them in a fixed order and reports which rule decided and why.
Bindings,
pattern → target. A pattern is a conversation-reference glob (*and[…];?always starts the conditions), optionally followed by?field=glob&…conditions on the message (%-escapes decoded,+kept): anativefield (labels,state, …),author(handle, native id or address) orgrade. A pattern without wildcards also matches the conversations under it, sogithub:example/appmatchesgithub:example/app#12.Thread continuity:
threadsmaps a thread root, a replied-to message id or a conversation reference to the target it already belongs to.Metadata rules: callables
message -> target | None, tried in order (metadata_rule()builds one fromfield=globconditions).The classifier: one optional callable, last, for what rules cannot see. It returns a target,
(target, reason), orNone.
Nothing matched: route returns None and the message is unrouted. What that means
(an operator queue, a drop) is the caller’s decision. A condition on a field the channel’s
messages never carry (?label= where GitHub messages carry labels) never matches;
check_binding() reports that when bindings are loaded.
>>> from correspond.testing import demo_message
>>> message = demo_message(conversation="github:example/app#12", labels=["partner:ada"])
>>> route(message, bindings={"github:example/app?labels=partner:*": "subject:app"})
RouteDecision(target='subject:app', rule='binding', reason='github:example/app?labels=partner:* matched github:example/app#12')
>>> route(message, bindings={"github:example/other": "subject:other"}) is None
True
Module Attributes
The order the chain runs in. |
|
Condition fields every message has, whatever its channel's |
Functions
|
The reason |
|
What would make a binding never match, found when bindings are loaded instead of by messages quietly going unrouted. |
|
A rule sending messages to |
|
Run the chain (bindings, thread continuity, metadata rules, classifier) and return the first decision, or |
Classes
|
Where a message goes, which rule decided, and why. |
- correspond.routing.MESSAGE_FIELDS = ('author', 'grade')#
Condition fields every message has, whatever its channel’s
nativefields.
- correspond.routing.RULES = ('binding', 'thread', 'metadata', 'classifier')#
The order the chain runs in.
- class correspond.routing.RouteDecision(*, target, rule, reason)[source]#
Bases:
objectWhere a message goes, which rule decided, and why.
- correspond.routing.binding_matches(pattern, message)[source]#
The reason
patternmatchesmessage, orNone.
- correspond.routing.check_binding(pattern, *, registry=None)[source]#
What would make a binding never match, found when bindings are loaded instead of by messages quietly going unrouted.
Reports a pattern without a channel, an unknown channel, a ref that is not in the channel’s canonical form (e.g. GitHub references are lower-cased by
parse_ref(), sobinding_matches, which compares the pattern literally, never matches a differently-cased pattern against it), and a condition on a field the channel’s messages never carry (itsnative_fields, plusauthorandgrade). A channel written as a wildcard, or one that does not declare its fields (native_fieldsisNone), is not checked for fields. A ref with wildcards, or one the channel’s own parser rejects outright, is not checked for canonical form – a malformed ref is a different problem than a mis-cased one.>>> from correspond.channels.github import GitHub >>> check_binding("github:example/app?labels=bug", registry={"github": GitHub()}) [] >>> check_binding("github:example/app?label=bug", registry={"github": GitHub()})[0].split(":")[0] 'the condition label=bug never matches' >>> check_binding("github:Example/App", registry={"github": GitHub()}) ["github:Example/App is not in canonical form: github references are normalised to 'github:example/app'; binding_matches compares refs literally, so this pattern will not match github:example/app"]
- correspond.routing.metadata_rule(target, *, name=None, **conditions)[source]#
A rule sending messages to
targetwhen everyfield=globcondition holds.>>> from correspond.testing import demo_message >>> rule = metadata_rule("urgent-queue", labels="priority:high") >>> rule(demo_message(labels=["priority:high"])), rule(demo_message()) ('urgent-queue', None)