Skip to content

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:

  • Sequence[TableCell]

    One or more TableCell objects representing logical item keys.

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.

Example

NumericRange(separator="..").expand(cell, context)

__post_init__ ⚓︎

__post_init__() -> None

Validate the configured separator after dataclass initialization.

Raises:

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:

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__ ⚓︎

__post_init__() -> None

Validate the configured separator after dataclass initialization.

Raises:

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.

Example

PrefixRepeat(separator=":")  # 3:Article

__post_init__ ⚓︎

__post_init__() -> None

Validate the configured separator after dataclass initialization.

Raises:

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:

  • list[TableCell]

    One logical value cell per key in the group.

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.

Example

SuffixRepeat(separator=" x")  # Article x3

__post_init__ ⚓︎

__post_init__() -> None

Validate the configured separator after dataclass initialization.

Raises:

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:

  • list[TableCell]

    One logical value cell per key in the group.

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

table_transformer = ColumnGroupExpander(
    key_row="IDs",
    range_rule=NumericRange(separator=".."),
    repeat_rule=PrefixRepeat(separator=":"),
)

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 TableData where 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:

  • list[TableCell]

    A list of TableCell objects produced by the range rule.

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:

  • list[TableCell]

    A list of TableCell objects produced by the repeat rule.

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 ⚓︎

_validate_separator(separator: str, rule_name: str) -> None

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:

Warning

Empty separators would make every cell look like rule syntax, so they are rejected at rule construction time.