State label membership by having no value - #950
Conversation
A label or annotation with a boolean value made a group's shape depend on its values' Python type, and left `false` as a label which validated and then projected nothing. Membership is now stated by carrying no value: `value` is `str | int | float | None`, default None, and true/false are refused by the value normalizer and the directory loader. The `1 == True` serializer workaround on OpticalPathLabel is no longer needed and is removed. The inventory tutorial gains a section stating the three interval shapes and the rules which follow from them.
|
Warning Review limit reached
Next review available in: 44 minutes Limit details: You’ve used all 2 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #950 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 195 195
Lines 24891 24895 +4
=========================================
+ Hits 24891 24895 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
✅ Documentation built: |
The annotation CSV writer builds each column as an object series, so an int beside an unset cell is no longer written as a float; an all-blank value column reloads with one dtype so a membership-only set round-trips equal; the directory loader reads a whitespace-only value cell as blank. The refusal messages now say a false row is deleted rather than blanked, and name the annotation group. Three tests guarding the deleted serializer override are removed.
true and false as values. The inventory plots were written before that and merged after it, so each branch was green against its own base and the pair broke on dev: a group which states membership loads from CSV into a string column, where its None reads back as NaN, and the renderer handed that to normalize_value, which refuses what is not finite. The inventory tutorial stopped building on that line. The renderer now takes #950's vocabulary rather than working around it. A row states membership by holding no value, whichever of None, NaN or NA the column's dtype produces; such a lane takes one color and is named by itself. Booleans are no longer a kind here either, since they are no longer a kind anywhere. A number missing from a numeric lane draws in the color which says nothing was stated, rather than raising.
Description
An inventory label (and an annotation) used to say "this interval is in group X" with a boolean value:
noisy,true. That made the group's shape — membership, which may overlap, versus function, which may not — depend on the Python type of its values, and leftfalseas a label that validated, serialized, and then projected to nothing (_fill_from_intervalsonly ever setTrue). It also needed a custom serializer onOpticalPathLabelto keep a value of1from being pruned as equal to the defaultTrue.This PR makes membership a matter of having no value:
OpticalPathLabel.valueandAnnotation.valuearestr | int | float | None, defaultNone. A label with no value states membership of its group; a label with a value states what the group holds there.true/falseare refused everywhere a value enters —normalize_value(both models), and_parse_labelsin the directory loader with the file and row named — with a message saying membership is spelled by leaving the value empty.value_kind(None) == "membership"replaces the"boolean"kind;_fill_from_intervalsunions membership intervals unconditionally. A group which states membership in one row and holds a value in another is a kind mix and is refused, in both the inventory and anAnnotationSet._write_object_typeoverride and_wantedhelper onOpticalPathLabelare deleted; with a default ofNone, nothing collides with1.The inventory tutorial gains a "The shape of a track" section stating the three interval shapes (tiling / function / membership), what an uncovered channel gets for each, that numeric groups project as float (absence is
NaN), the one-name-one-coordinate rule, and the half-open-with-run-end fencepost projection applies. Its labels CSV now writes150,300,noisy,.Projection and selection are unchanged: a membership group still projects as a bool coordinate,
spool.select(noisy=True)/expand_by("noisy")behave as before.Follow-ups from a six-way adversarial review (Codex + five lenses):
AnnotationSetCSV writer builds each column as an object series, so an int beside an unset cell is written as5, not5.0(pandas inferred a float column from theNone). Note that pandas does the same inference when constructing a frame from a plain list, so an in-memory frame mixing ints with unset rows should passdtype=object; a table read back is already an object column.valuecolumn) now reloads equal to what was saved; the reader had inferred a string dtype from nothing.valuecell as blank, since a blank cell is now load-bearing.falserow should become — deleted, not blanked — since blanking it would turn an exclusion into membership. The annotation-side refusal names the group.True); the message says a blank cell states membership.Changelog
OpticalPathLabelandAnnotationvalues may no longer be booleans; a label with no value states membership of its group, andtrue/falsecells are refused with a message saying so.OpticalPathLabelorAnnotationwith no value now reads back withvalue=Nonerather thanTrue.value=falseno longer validates and then silently projects nothing.AnnotationSetwritten to CSV keeps an integer value an integer when another row of the column is unset.Checklist
I have:
docs/contributing/general_guidelines.qmd).I have (if applicable):