neu_mark.rules¶
The @rule decorator and RuleSet: declaring how annotation strings become facets.
A plain rule is any callable taking one row and returning a value, a sequence, or
None; neu_mark.explore accepts those. A Rule is that callable plus its
declarations (see rule()), which neu_mark.segprops.build() needs in order to
know which rules mint tags, which exclude a body, and what each facet is called. Explore
with plain callables; publish with a RuleSet.
A rules module is dataset content (which prefixes are neuropils, which suffixes mark
completeness), kept with the body lists and loaded by path with from_module(). Nothing
is built in. The module names its label column once (LABEL = "instance"); a rule that
declares no needs reads that column, and test, remainder and explain fill it.
>>> RULES = RuleSet([side, column], label="instance")
>>> RULES["side"].test("Tm2_A2(L)")
'L'
>>> RULES.explain("LN_C5(L)_NCL")
{'side': 'L', ...}
>>> RULES.remainder("LN_C5(L)_NCL") # what no rule accounted for
'LN'
Attributes¶
Classes¶
Functions¶
|
Load a rules module by file path. |
|
A record of the rules that produced an output. |
|
Declare a function as a rule. Usable bare ( |
Module Contents¶
- class neu_mark.rules.Rule(func: Callable, *, name: str | None = None, needs: Sequence[str] | None = None, multi: bool = False, tag: bool = True, prefix: str | None = None, description: str | None = None, drop: bool = False, consumes: Iterable[str] | Callable | None = None)¶
One named facet derived from a row. Callable exactly like the function it wraps.
- bound(label: str | None) Rule¶
A copy reading
labelas the label column; this rule is left as it is.
- consumed(row) tuple[str, ...]¶
The tokens of the source string this rule accounts for.
A rule that does not read the label column consumes nothing, so a rule returning the curated
typecannot remove the token a cell-type remainder wants to keep.
- remainder(_value: str | None = None, /, **fields) str | None¶
The label string with this rule’s tokens removed, rejoined with
_.Removal is by token (the strings are
_- and parenthesis-delimited), not by substring, soside’s"L"does not eat theLofLC10.
- scalar(row) Any¶
The rule’s single value, or
None. For the single-valued kinds:dropreasons and the reservedlabelrule, where a tuple would only be unwrapped.
- set_kwargs(**kwargs) Self¶
Bind keyword arguments of the rule’s function, in place. Returns the rule.
- test(_value: str | None = None, /, **fields) Any¶
Evaluate on one synthetic row;
rule.test("Tm2_A2(L)")fills the label column.Returns the rule’s own return value. Missing fields arrive as
None, as in a run.
- values(row) tuple¶
The rule’s output as a tuple, validated against
multi.
- description¶
- drop = False¶
- func¶
- label: str | None = None¶
- multi = False¶
- name¶
- property needs: tuple[str, ...]¶
The columns the rule reads: those it declares, else the label column.
- prefix¶
- tag = True¶
- class neu_mark.rules.RuleSet(rules: Iterable[Rule] | Mapping[str, Callable], *, keep: Sequence[str] | None = None, source: str | None = None, label: str | None = None)¶
An ordered collection of rules, plus the reports for iterating on them.
- apply(frame: pandas.DataFrame) pandas.DataFrame¶
Every rule over every row: one column per rule, values as tuples.
- as_mapping() dict[str, Callable]¶
{name: callable}, for theneu_mark.explorefunctions.
- consumed(_value: str | None = None, /, **fields) dict[str, tuple]¶
{rule: tokens}for every rule that accounted for part of the string.
- coverage(frame: pandas.DataFrame, *, top: int = 3) pandas.DataFrame¶
Per-rule coverage, with each rule’s declared facts alongside.
- describe() pandas.DataFrame¶
What every rule declares, one row per rule in evaluation order. (
coverage()reports what they did to a frame.)
- dropping(names: Iterable[str]) RuleSet¶
This set with the named rules turned into drop rules, keeping their own test.
Each is replaced in place by a rule with the same function and
needs, so the body it fires on is excluded rather than tagged. An unknown name is refused.
- explain(_value: str | None = None, /, **fields) dict¶
Every rule’s output for one synthetic row: a scalar for single-valued rules, a tuple for multi-valued ones.
- override(other: RuleSet | Iterable[Rule] | Mapping[str, Callable]) RuleSet¶
This set with
other’s rules replacing same-named ones, others appended.A replacement keeps the position of the rule it replaces, so evaluation order is unchanged. (
__init__refuses duplicate names; overriding is how a dataset module redefines a builtin.)
- remainder(_value: str | None = None, /, **fields) str | None¶
The string with every token any rule accounted for removed, so a cell-type parse need not repeat the rules’ vocabularies.
The removed tokens are one union, so the result does not depend on rule order. The result is a residue, not a cell type: often a bare neuropil name for an unidentified body.
- require(frame: pandas.DataFrame) None¶
Check every rule’s
needsagainst a frame, naming the rule that is unmet.
- unparsed(frame: pandas.DataFrame, name: str, *, column: str | None = None) pandas.DataFrame¶
The strings one rule did not fire on, ranked by bodies. The iteration loop.
columndefaults to the label column.
- property drops: list[Rule]¶
The rules that exclude a body. Evaluated first, so an excluded body does not count toward other rules’ coverage.
- keep¶
- label = None¶
- property names: list[str]¶
- rules¶
- source = None¶
- neu_mark.rules.from_module(path: str | pathlib.Path, *, variable: str = 'RULES') RuleSet¶
Load a rules module by file path.
Uses the module’s
RULESif it defines one; otherwise every@ruleat module level, in declaration order. The module’sLABELnames its label column (seeRuleSet); aRULESthat names a different one is refused.
- neu_mark.rules.provenance(ruleset: RuleSet, *, embed: bool = True, max_embed_bytes: int = MAX_EMBED_BYTES) dict¶
A record of the rules that produced an output.
Each rules source file is embedded verbatim with its sha256, so the record does not depend on the file still existing; git commit, remote and dirty flag are added if the file is in a work tree. Files are found from each rule’s
__code__.co_filename, so helpers imported from sibling files are included; files insideneu_markare not.
- neu_mark.rules.rule(func: Callable | None = None, /, *, needs: Sequence[str] | None = None, multi: bool = False, tag: bool = True, prefix: str | None = None, name: str | None = None, description: str | None = None, drop: bool = False, consumes: Iterable[str] | Callable | None = None)¶
Declare a function as a rule. Usable bare (
@rule) or called (@rule(...)).needs: the columns the rule reads, checked up front. Left out, the rule reads the label column of theRuleSetit is bound into.multi: whether the facet can have several values. A single-valued rule that returns several raises, which catchesre.findallused wherere.searchwas meant.prefix: the tag namespace, defaulting to the rule’s name (glomerulus:VA1v);prefix=""mints a bare tag.drop: the rule excludes the body it fires on, returning the reason.consumes: the tokens it accounts for, forRuleSet.remainder().tag=False: the rule produces a property, not a tag (seeRESERVED).
The docstring’s first line becomes the description shown in reports and in the published
tag_descriptions. A rule may read a column an earlier rule produced.
- neu_mark.rules.MAX_EMBED_BYTES = 262144¶
- neu_mark.rules.RESERVED = ('label', 'description')¶
- neu_mark.rules.logger¶