Column Group Expansion⚓︎
group_expansion
⚓︎
Declarative expansion helpers for grouped column-oriented Gherkin data tables.
The helpers in this module cover a common table shape: the first row contains one key or ID cell per source group, and every other row contains one value for that same group. A key cell may expand into several logical item columns. The corresponding value cells are then repeated or copied across those columns.
The package supplies reusable mechanics and a few explicit rule objects. It
does not require these conventions. Projects can provide their own range and
repeat rules, or bypass this layer by overriding transform_table().
Info
Expansion preserves source coordinates. Logical cells produced from a compact source cell still point back to the feature text that created them.
_ExpansionLimitError
⚓︎
Bases: ValueError
Signal that a built-in expansion exceeded its private safety bound.
RangeRule
⚓︎
Bases: Protocol
Contract for turning one key cell into one or more logical keys.
Info
Custom range rules can implement any project convention, such as numeric ranges, alphabetic ranges, or domain-specific IDs.
expand
⚓︎
expand(cell: TableCell, context: ParseContext) -> Sequence[TableCell]
Return logical key cells derived from cell.
A value that does not use the rule's special syntax should normally
return [cell]. Invalid recognized syntax may raise ValueError;
ColumnGroupExpander converts it into a source-aware
TableError.
Parameters:
-
cell(TableCell) –Source key cell from the grouped table.
-
context(ParseContext) –Parse context for the current schema parse.
Returns:
Warning
Return TableCell objects, not raw strings. Use
cell.with_value(...) so diagnostics still point to the compact
source cell.
RepeatRule
⚓︎
Bases: Protocol
Contract for spreading one value cell across a logical key group.
Info
Repeat rules own value syntax only. The expander owns table shape,
row iteration, count checks, and TableData construction.
expand
⚓︎
expand(
cell: TableCell, expected_count: int, context: ParseContext
) -> Sequence[TableCell]
Return exactly expected_count logical value cells.
A value without repeat syntax should normally be copied across the
group. Invalid recognized syntax may raise ValueError.
Parameters:
-
cell(TableCell) –Source value cell aligned with a grouped key cell.
-
expected_count(int) –Number of logical key cells in the group.
-
context(ParseContext) –Parse context for the current schema parse.
Returns:
Warning
Count mismatches are treated as table errors because they would produce ambiguous record values.
NumericRange
dataclass
⚓︎
NumericRange(separator: str = '..')
Expand inclusive ascending integer ranges such as 1..4.
Values without the configured separator are treated as one literal key. Once the separator is present, both endpoints must be integers and the first endpoint must not exceed the second.
Attributes:
-
separator(str) –Text separating the inclusive start and end values.
__post_init__
⚓︎
Validate the configured separator after dataclass initialization.
Raises:
-
ValueError–If
separatoris empty.
Warning
Validation happens eagerly so an invalid schema fails during setup rather than during the first feature parse.
expand
⚓︎
expand(cell: TableCell, context: ParseContext) -> list[TableCell]
Return one literal key or an inclusive integer-key sequence.
Parameters:
-
cell(TableCell) –Key cell to inspect for range syntax.
-
context(ParseContext) –Parse context for the current schema parse.
Returns:
-
list[TableCell]–[cell]for literal values, or generated cells for every integer -
list[TableCell]–in the inclusive range.
Raises:
-
ValueError–If recognized range syntax is malformed or descending.
Info
Generated cells keep the source row, source column, and source
value from cell.
AlphabeticRange
dataclass
⚓︎
AlphabeticRange(separator: str = '-')
Expand inclusive ASCII letter ranges such as A-D or a-d.
Endpoints must each be one ASCII letter and use the same case. Values without the configured separator remain literal keys.
Attributes:
-
separator(str) –Text separating the inclusive start and end letters.
Warning
Only single ASCII letters are supported. Use a custom range rule for multi-character labels, Unicode collation, or domain-specific IDs.
__post_init__
⚓︎
Validate the configured separator after dataclass initialization.
Raises:
-
ValueError–If
separatoris empty.
Info
Keeping this check on the rule object makes custom expander failures easier to diagnose.
expand
⚓︎
expand(cell: TableCell, context: ParseContext) -> list[TableCell]
Return one literal key or an inclusive letter-key sequence.
Parameters:
-
cell(TableCell) –Key cell to inspect for alphabetic range syntax.
-
context(ParseContext) –Parse context for the current schema parse.
Returns:
-
list[TableCell]–[cell]for literal values, or generated cells for each ASCII -
list[TableCell]–letter in the inclusive range.
Raises:
-
ValueError–If recognized range syntax is malformed or descending.
Info
Case must match between endpoints so A-D and a-d are clear,
while A-d is rejected.
PrefixRepeat
dataclass
⚓︎
PrefixRepeat(separator: str = ':')
Expand count-before-value syntax such as 3:Article.
If the text before the separator is not an integer, the entire value is
treated as a literal and copied across the key group. This allows normal
text containing the separator, such as News: Europe, to remain valid.
Attributes:
-
separator(str) –Text between repeat count and repeated value.
__post_init__
⚓︎
Validate the configured separator after dataclass initialization.
Raises:
-
ValueError–If
separatoris empty.
Warning
A blank separator would make prefix parsing ambiguous for every cell value.
expand
⚓︎
expand(cell: TableCell, expected_count: int, context: ParseContext) -> list[TableCell]
Repeat recognized syntax or copy a literal value across a group.
Parameters:
-
cell(TableCell) –Value cell aligned with a grouped key cell.
-
expected_count(int) –Number of logical keys in the group.
-
context(ParseContext) –Parse context for the current schema parse.
Returns:
Raises:
-
ValueError–If recognized repeat syntax is empty or has the wrong count.
Info
Non-numeric prefixes are treated as literal values so ordinary text containing the separator remains usable in feature files.
SuffixRepeat
dataclass
⚓︎
SuffixRepeat(separator: str = ' x')
Expand value-before-count syntax such as Article x3.
If the text after the final separator is not an integer, the entire value is treated as a literal and copied across the key group.
Attributes:
-
separator(str) –Text between repeated value and repeat count.
__post_init__
⚓︎
Validate the configured separator after dataclass initialization.
Raises:
-
ValueError–If
separatoris empty.
Info
Eager validation keeps invalid rule configuration close to schema import time.
expand
⚓︎
expand(cell: TableCell, expected_count: int, context: ParseContext) -> list[TableCell]
Repeat recognized syntax or copy a literal value across a group.
Parameters:
-
cell(TableCell) –Value cell aligned with a grouped key cell.
-
expected_count(int) –Number of logical keys in the group.
-
context(ParseContext) –Parse context for the current schema parse.
Returns:
Raises:
-
ValueError–If recognized repeat syntax is empty or has the wrong count.
Warning
The final occurrence of separator is used. Choose separators
that do not naturally appear at the end of domain values.
ColumnGroupExpander
dataclass
⚓︎
ColumnGroupExpander(key_row: str, range_rule: RangeRule, repeat_rule: RepeatRule)
Expand grouped columns using replaceable range and repeat rules.
Parameters:
-
key_row(str) –Literal label expected in the first cell of the first row.
-
range_rule(RangeRule) –Object implementing :class:
RangeRule. -
repeat_rule(RepeatRule) –Object implementing :class:
RepeatRule.
The expander owns the repetitive table mechanics: rectangular-shape
checks, group iteration, source preservation, count validation, and
TableData construction. Rule objects own syntax recognition and value
expansion.
Example
transform
⚓︎
transform(
table: TableData, context: ParseContext, *, schema: type | str | None = None
) -> TableData
Return an expanded logical table ready for schema parsing.
Parameters:
-
table(TableData) –Source-aware grouped table.
-
context(ParseContext) –Parse context for the current schema parse.
-
schema(type | str | None, default:None) –Optional schema identity used in diagnostics.
Returns:
-
TableData–A rectangular
TableDatawhere grouped columns have been -
TableData–expanded into one logical record column per key.
Raises:
-
TableError–If the table is empty, non-rectangular, has the wrong key row, or a custom rule returns invalid cells.
Warning
This transformer expects a column-oriented grouped shape. Use a
custom transform_table() override for unrelated compact table
conventions.
_expand_range
⚓︎
_expand_range(
cell: TableCell, context: ParseContext, schema: type | str | None
) -> list[TableCell]
Run a range rule and normalize its errors.
Parameters:
-
cell(TableCell) –Source key cell to expand.
-
context(ParseContext) –Parse context for the current schema parse.
-
schema(type | str | None) –Optional schema identity used in diagnostics.
Returns:
Raises:
-
TableError–If the rule raises a table error, raises another exception, or returns non-cell values.
Info
Custom ValueError failures are wrapped with source-cell
coordinates so feature authors see the compact key cell.
_expand_repeat
⚓︎
_expand_repeat(
cell: TableCell,
expected_count: int,
context: ParseContext,
schema: type | str | None,
) -> list[TableCell]
Run a repeat rule and normalize its errors.
Parameters:
-
cell(TableCell) –Source value cell to expand.
-
expected_count(int) –Number of logical cells required.
-
context(ParseContext) –Parse context for the current schema parse.
-
schema(type | str | None) –Optional schema identity used in diagnostics.
Returns:
Raises:
-
TableError–If the rule raises a table error, raises another exception, or returns non-cell values.
Warning
This method validates object type only. The public transform
method additionally checks that the returned count matches the key
group size.
_require_cells
staticmethod
⚓︎
_require_cells(
cells: Sequence[object],
source: TableCell,
rule_name: str,
schema: type | str | None,
) -> None
Ensure custom rules return TableCell instances.
Parameters:
-
cells(Sequence[object]) –Objects returned by a range or repeat rule.
-
source(TableCell) –Source cell used when reporting invalid return values.
-
rule_name(str) –Human-readable rule family for diagnostics.
-
schema(type | str | None) –Optional schema identity used in diagnostics.
Raises:
-
TableError–If any returned object is not a
TableCell.
Warning
Returning raw strings would lose source coordinates. Custom rules
should call source.with_value(...) for transformed cells.
_validate_separator
⚓︎
Reject empty separators.
Parameters:
-
separator(str) –Separator configured on a range or repeat rule.
-
rule_name(str) –Human-readable rule name for the error message.
Raises:
-
ValueError–If
separatoris empty.
Warning
Empty separators would make every cell look like rule syntax, so they are rejected at rule construction time.