-
Notifications
You must be signed in to change notification settings - Fork 3
feat: support custom field ordering and subsetting in Metric.write() #269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
📝 WalkthroughWalkthroughAdded class-level write ordering via new classmethod Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/fgpyo/util/test_metric.py (1)
997-997: Optional: Prefix unused parameter to silence linter.The
field_typesparameter is required by the method signature but unused in these simple test implementations. Consider prefixing with_to indicate intentional:-def _fields_to_write(cls, field_types: List[FieldType]) -> List[str]: +def _fields_to_write(cls, _field_types: List[FieldType]) -> List[str]:Not a functional issue—just silences static analysis warnings.
Also applies to: 1026-1026, 1104-1104, 1135-1135, 1160-1160, 1177-1177, 1195-1195
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
fgpyo/util/metric.py(4 hunks)tests/fgpyo/util/test_metric.py(2 hunks)
🧰 Additional context used
🪛 Ruff (0.14.8)
fgpyo/util/metric.py
412-414: Avoid specifying long messages outside the exception class
(TRY003)
419-421: Avoid specifying long messages outside the exception class
(TRY003)
tests/fgpyo/util/test_metric.py
997-997: Unused class method argument: field_types
(ARG003)
1026-1026: Unused class method argument: field_types
(ARG003)
1104-1104: Unused class method argument: field_types
(ARG003)
1135-1135: Unused class method argument: field_types
(ARG003)
1160-1160: Unused class method argument: field_types
(ARG003)
1177-1177: Unused class method argument: field_types
(ARG003)
1195-1195: Unused class method argument: field_types
(ARG003)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Tests (3.9)
🔇 Additional comments (8)
tests/fgpyo/util/test_metric.py (2)
32-32: LGTM - required import for new feature.The
FieldTypeimport is needed for the_fields_to_write()method signature in test fixtures.
987-1210: Excellent test coverage for the new field ordering features.The nine new test functions comprehensively cover:
- Field reordering and subsetting via
_fields_to_write()- Call-level
include_fieldsandexclude_fields- Precedence (include_fields overrides class-level ordering)
- Roundtrip behavior with optional fields
- Error cases (non-existent fields, duplicates)
- Order preservation when using exclude_fields
All tests verify both header output and actual file contents, and are parametrized for both attr and dataclasses implementations.
fgpyo/util/metric.py (6)
114-149: Clear documentation with helpful examples.The added documentation effectively explains both class-level (
_fields_to_write()) and call-level (include_fields/exclude_fields) customization options, with practical guidance on when to use each approach.
370-401: Well-designed extension point.The
_fields_to_write()hook provides clean class-level customization. Default implementation preserves original behavior, and the docstring clearly distinguishes between class-level overrides and call-level parameters.
402-423: Robust validation logic.The updated
header()method correctly validates that_fields_to_write()returns only valid, non-duplicate field names. Catches configuration errors early.
339-368: Clean API extension.Adding
include_fieldsandexclude_fieldsparameters maintains backward compatibility while providing call-level control. The delegation toMetricWriteris straightforward.
717-726: Correct ordering implementation.Using
metric_class.header()instead oflist(metric_class.keys())ensures thatexclude_fieldsrespects the class-level field ordering from_fields_to_write(). This maintains the correct precedence hierarchy.
182-182: Required import for type hints.The
FieldTypeimport is necessary for the_fields_to_write()method signature.
9be384a to
6dd86b7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
fgpyo/util/metric.py (1)
416-421: Minor: O(n²) duplicate detection.Using
header.count(h) > 1is O(n²). For small headers this is fine, but aCounteror seen-set approach would be O(n).+ from collections import Counter # Validate no duplicates - if len(header) != len(set(header)): - duplicates = [h for h in header if header.count(h) > 1] + counts = Counter(header) + if len(header) != len(counts): + duplicates = [h for h, c in counts.items() if c > 1] raise ValueError( f"_fields_to_write() returned duplicate fields: {', '.join(set(duplicates))}" )
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
fgpyo/util/metric.py(4 hunks)tests/fgpyo/util/test_metric.py(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
fgpyo/util/metric.py (2)
tests/fgpyo/util/test_metric.py (6)
_fields_to_write(174-175)_fields_to_write(183-184)_fields_to_write(199-200)_fields_to_write(208-209)_fields_to_write(1163-1164)_fields_to_write(1180-1181)fgpyo/util/inspect.py (1)
get_fields(404-413)
tests/fgpyo/util/test_metric.py (1)
fgpyo/util/metric.py (6)
Metric(204-536)_fields_to_write(371-400)header(403-423)write(339-368)write(652-675)read(249-325)
🪛 Ruff (0.14.8)
fgpyo/util/metric.py
412-414: Avoid specifying long messages outside the exception class
(TRY003)
419-421: Avoid specifying long messages outside the exception class
(TRY003)
tests/fgpyo/util/test_metric.py
174-174: Unused class method argument: field_types
(ARG003)
183-183: Unused class method argument: field_types
(ARG003)
199-199: Unused class method argument: field_types
(ARG003)
208-208: Unused class method argument: field_types
(ARG003)
1163-1163: Unused class method argument: field_types
(ARG003)
1180-1180: Unused class method argument: field_types
(ARG003)
🔇 Additional comments (6)
tests/fgpyo/util/test_metric.py (2)
168-209: LGTM on new test metric classes.These test variants properly exercise the
_fields_to_write()API for reordering, subsetting, and error scenarios. The unusedfield_typesparameter flagged by Ruff is intentional—these test implementations return hardcoded lists to verify specific behaviors while conforming to the interface signature.
1035-1205: Comprehensive test coverage for the new feature.Tests cover reordering, subsetting, include/exclude parameters, precedence behavior, roundtrip with optional fields, and error cases. Good parametrization for both attr and dataclasses.
fgpyo/util/metric.py (4)
370-400: Well-designed extension point.The
_fields_to_write()method provides a clean hook for subclass customization with a sensible default. Documentation is thorough.
719-726: Correctly integrates class-level ordering.Using
header()for exclude and default cases ensures_fields_to_write()ordering is respected.include_fieldscorrectly bypasses this to allow call-time override.
338-368: Clean API extension.Parameters delegate to
MetricWriterwhere validation occurs. Docstring clearly explains precedence behavior.
114-149: Excellent documentation.Clear examples for both class-level and call-level customization with practical guidance on when to use each.
6dd86b7 to
bae093f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
tests/fgpyo/util/test_metric.py (1)
168-210: Consider prefixing unusedfield_typeswith underscore.The
field_typesparameter is unused in these test implementations (static analysis ARG003). Prefix with_to indicate intentional non-use:-def _fields_to_write(cls, field_types: List[FieldType]) -> List[str]: +def _fields_to_write(cls, _field_types: List[FieldType]) -> List[str]:Apply this pattern to all test metric classes (lines 174, 183, 199, 208).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
fgpyo/util/metric.py(4 hunks)tests/fgpyo/util/test_metric.py(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/fgpyo/util/test_metric.py (1)
fgpyo/util/metric.py (5)
Metric(205-538)_fields_to_write(372-401)header(404-425)write(340-369)write(654-677)
fgpyo/util/metric.py (3)
tests/fgpyo/util/test_metric.py (6)
_fields_to_write(174-175)_fields_to_write(183-184)_fields_to_write(199-200)_fields_to_write(208-209)_fields_to_write(1163-1164)_fields_to_write(1180-1181)fgpyo/sam/builder.py (1)
header(586-588)fgpyo/util/inspect.py (1)
get_fields(404-413)
🪛 Ruff (0.14.8)
tests/fgpyo/util/test_metric.py
174-174: Unused class method argument: field_types
(ARG003)
183-183: Unused class method argument: field_types
(ARG003)
199-199: Unused class method argument: field_types
(ARG003)
208-208: Unused class method argument: field_types
(ARG003)
1163-1163: Unused class method argument: field_types
(ARG003)
1180-1180: Unused class method argument: field_types
(ARG003)
fgpyo/util/metric.py
413-415: Avoid specifying long messages outside the exception class
(TRY003)
421-423: Avoid specifying long messages outside the exception class
(TRY003)
🔇 Additional comments (8)
fgpyo/util/metric.py (6)
154-154: LGTM: Imports are appropriate.Both imports are used correctly in the implementation.
Also applies to: 183-183
114-149: LGTM: Documentation is clear and comprehensive.The examples effectively illustrate when to use each approach.
340-369: LGTM: Backward-compatible signature extension.The new parameters are optional and well-documented.
371-401: LGTM: Well-designed extension point.The default implementation preserves existing behavior, and the docstring provides clear guidance on when to override.
403-425: LGTM: Validation logic is sound.The validation catches invalid field references and duplicates. The static analysis TRY003 hints are acceptable here since error messages include dynamic field names for clarity.
695-730: LGTM: Internal ordering respects class-defined field order.The use of
header()ensures that_fields_to_write()customizations are honored throughout the write path.tests/fgpyo/util/test_metric.py (2)
219-223: LGTM: Test metrics properly integrated.All new metrics are added to the DataBuilder consistently.
1030-1205: LGTM: Comprehensive test coverage.Tests cover reordering, subsetting, parameter interactions, validation errors, and roundtrip behavior. The parameterization ensures coverage for both attr and dataclasses implementations.
Supersedes #178.
Adds two ways to customize which fields are written and in what order:
_fields_to_write()for consistent ordering across all writesinclude_fieldsorexclude_fieldstowrite()The call-level approach takes precedence, following the pattern of
csv.DictWriter.Fixes #177