Skip to content

Let an author keep a column to themselves - #993

Open
d-chambers wants to merge 2 commits into
devfrom
table-private-columns
Open

Let an author keep a column to themselves#993
d-chambers wants to merge 2 commits into
devfrom
table-private-columns

Conversation

@d-chambers

@d-chambers d-chambers commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Description

Operators want somewhere to write down how something was actually deployed — who backfilled a trench, which drawing a run came from — beside the rows it is about, in the CSV they already maintain. Today a column the format does not model is refused: notes reaches the model as an unknown field and raises a pydantic error which names attrs.yaml rather than the CSV.

This adds one rule, in the shape the inventory format already uses for files: a column whose header begins with an underscore is the author's own, and no reader looks for meaning in it. _crew, _drawing, _who_backfilled_it — the values stay in the file, and nothing types them, checks them against a declaration, or refuses them. It is the same bargain as a hidden file: the module docstring already says loading is "strict about near-misses and indifferent to clean misses", and a private header is a column declining to participate.

The name can never collide with a field a model might later add, since pydantic makes a leading underscore a private attribute rather than a field.

Two formats read hand-authored tables, and both take the rule. The inventory drops private columns as each track table is read, before the geometry table's numeric rule or the model's unknown-field check can see them. Annotation sets drop them where a frame enters the set, so a set built in memory and a set read from a file hold the same columns and no set writes a column it could not read back; stored sets also drop them before any cell is typed, so a dtype declared for a private column is not checked against it.

A note which should travel with the data still belongs in a field the model has — every inventory object has description, and a description column already worked before this PR.

Rows a table cannot write

Dropping columns exposed an older silent loss, which the CLI review caught: a frame with rows and no columns built a set of that many annotations, and writing it produced a table with no rows, so a saved set came back shorter than the one which wrote it. That is now refused where what went missing can still be named — for a table whose every column is private, for a frame which never had one, and with the file named when it came from one.

Two smaller findings from the same review: a set may no longer declare a dimension beginning with an underscore (a dimension is stated by a column, and no set reads a private one), and _read_cells keeps the index of the table it read, so a row is not lost between the file and the set.

Changelog

  • added: a CSV column whose header begins with an underscore is the author's own record keeping; inventory tables and annotation sets read past it, so field crews can keep notes beside the rows they describe.
  • fixed: an annotation set whose rows state no column is refused, rather than being written out as a set with no rows.
  • changed: an annotation set may no longer declare a dimension whose name begins with an underscore.

Checklist

I have:

  • filled in the Changelog section above (see docs/contributing/general_guidelines.qmd).

I have (if applicable):

  • referenced the GitHub issue this PR closes.
  • documented the new feature with docstrings and/or appropriate doc page.
  • included tests. See testing guidelines.
  • added the "ready_for_review" tag once the PR is ready to be reviewed.

Summary by CodeRabbit

  • New Features

    • Added support for underscore-prefixed private metadata columns in annotation and inventory tables.
    • Private columns are ignored during loading, validation, serialization, and dimension processing.
    • Added a utility for removing private columns from tabular data.
  • Bug Fixes

    • Preserved rows when tables contain only private columns.
    • Added clear validation errors for tables with no usable public columns.
  • Documentation

    • Clarified private-column conventions and recommended using description for notes that should be retained.

A CSV header beginning with an underscore is the crew's own record
keeping -- who backfilled a trench, which drawing a run came from -- and
no reader looks for meaning in it. This is the rule the inventory format
already applies to files, applied to columns: strict about near-misses,
indifferent to clean misses.

The name can never collide with a field a model might later add, since
pydantic makes a leading underscore a private attribute rather than a
field.

Annotations read it the same way, at the frame boundary rather than the
file one, so a set holds what a stored set holds and never writes a
column it could not read back.
Three findings from the CLI review of the private-column rule.

A frame of rows and no columns built a set which wrote nothing: a saved
set came back shorter than the one which wrote it. Refused now, where
what went missing can still be named -- for a table whose every column is
private, and for a frame which never had one.

A dimension may not begin with an underscore, since a dimension is stated
by a column and no set reads a private one.

Stored sets drop private columns before any cell is read, so a
declaration a private column cannot meet is no longer checked against it,
and a table read from a file states the same set the frame does.
@d-chambers d-chambers added the ready_for_review PR is ready for review label Aug 22, 2026
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8cd392a7-26ee-4157-a167-76d9e20bad31

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1d149 and bba420a.

📒 Files selected for processing (9)
  • dascore/core/annotation_loader.py
  • dascore/core/annotations.py
  • dascore/core/inventory_loader.py
  • dascore/utils/tables.py
  • docs/tutorial/inventory.qmd
  • tests/test_core/test_annotation_loader.py
  • tests/test_core/test_annotations.py
  • tests/test_core/test_inventory_loader.py
  • tests/test_utils/test_tables.py

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

The change adds underscore-prefixed private columns to annotation and inventory table handling. Shared filtering removes these columns before typing and validation. Rows without readable columns raise errors. Tests and inventory documentation cover the behavior.

Changes

Private column handling

Layer / File(s) Summary
Shared private-column filter
dascore/utils/tables.py, tests/test_utils/test_tables.py
Adds PRIVATE_PREFIX and drop_private_columns. Tests cover filtering, identity preservation, non-mutation, and underscore placement.
AnnotationSet private-column validation
dascore/core/annotations.py, tests/test_core/test_annotations.py
Annotation sets remove private columns, reject private dimensions, exclude private bounds and extras, and reject rows with no readable columns.
Annotation table loading
dascore/core/annotation_loader.py, tests/test_core/test_annotation_loader.py
Annotation CSV and parquet tables filter private columns before cell typing. Table indexes remain intact, and private-only tables raise errors.
Inventory table loading
dascore/core/inventory_loader.py, docs/tutorial/inventory.qmd, tests/test_core/test_inventory_loader.py
Inventory loading removes private columns before geometry and structural validation. Documentation and tests define ignored private metadata and required public columns.

Merge Risk: ⚪ Minimal · up to bba42

The change allows leading-underscore author columns while preserving existing modeled data behavior and adds safeguards against row loss; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: allowing authors to keep private columns in tables.
Description check ✅ Passed The description clearly explains the feature, affected formats, behavior, tests, documentation, and review findings.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 34 functions across 8 files. (1 skipped: 1 unsupported.)
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch table-private-columns

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (5d1d149) to head (bba420a).

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #993   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          202       202           
  Lines        27343     27364   +21     
=========================================
+ Hits         27343     27364   +21     
Flag Coverage Δ
network 39.20% <12.50%> (-0.02%) ⬇️
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bba420a827

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 314 to +317
frame, _ = read_parquet(path, what=what, empty=True)
if not len(frame.columns):
return None
frame = _kept_columns(frame, path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Filter private Parquet columns before document decoding

When an annotation Parquet file marks an underscore-prefixed column in dascore:documents, read_parquet() parses and validates that column's JSON before _kept_columns() removes it. Consequently, malformed or otherwise non-DASCore content in a private column still raises ParameterError, unlike the CSV path and contrary to the rule that private-column contents are never interpreted. The private columns need to be excluded before read_parquet() performs document-column decoding.

Useful? React with 👍 / 👎.

Comment on lines 1688 to +1689
@pytest.mark.skipif(pyarrow is None, reason="pyarrow is not installed")
class TestPrivateColumns:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the PyArrow skip marker to the Parquet tests

When PyArrow is not installed, this insertion attaches the existing skipif marker to the new CSV-only TestPrivateColumns class and leaves the following TestParquet class unmarked. The supported no-PyArrow test environment will therefore skip the tests that need no optional dependency while running the Parquet tests, which call to_parquet() and _forge() and fail because PyArrow is absent; move or duplicate the marker so it still decorates TestParquet.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready_for_review PR is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant