Skip to content

Added KDocs and tests for constructors.kt public APIs - #2213

Draft
zaleslaw wants to merge 1 commit into
masterfrom
issue-1955
Draft

zaleslaw wants to merge 1 commit into
masterfrom
issue-1955

Conversation

@zaleslaw

@zaleslaw zaleslaw commented Nov 4, 2026

Copy link
Copy Markdown
Collaborator

Closes #1954, closes #1955

About 50 public declarations in api/constructors.kt had no KDoc, and the constructor families had
minimal test coverage. This PR documents every non-deprecated public API there and pins its behaviour
with tests: name generation, row-major fill, type-inference bounds and the thrown exceptions.

Files

File What changed
core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/constructors.kt KDoc for the column/valueColumn/columnGroup/frameColumn families, ColumnDelegate, columnOf/column, the previously undocumented dataFrameOf overloads, DataFrameBuilder members, pathOf
core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/ConstructorsDocs.kt (new) two shared KoDEx fragments: column-reference usage and the dataFrameOf contract with @throws
core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/documentation/DocumentationUrls.kt new PathOf alias → columnselectors.html#column-resolvers
core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/constructors.kt 42 new tests
core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/columnAccessors.kt (new) ColumnAccessorsTests: the accessor families
core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/Create.kt 7 new documentation samples, incl. a Properties/Strings tab pair
docs/StardustDocs/topics/createColumn.md, createDataFrame.md, ColumnSelectors.md new ### column section, columnOf type nuances, DataFrameBuilder fill/random, pathOf in Column Resolvers; column added to the API-reference line

Problem 1: random* range bounds are asymmetric

  • Problem: dataFrameOf("x").randomLong(100, 1L..2L) never yields 2L, while randomInt(100, 1..2)
    yields both 1 and 2: the ClosedRange overloads pass endInclusive to Random.nextLong(from, until),
    where it is excluded, but randomInt(IntRange) includes both bounds.
  • Options: document the actual bounds; or change the implementation to include endInclusive
    (a behaviour change beyond this PR).
  • Chosen: the @param [range] docs state the bounds per function; behaviour is unchanged.
  • Test: builder random columns have declared types and stay in range pins
    randomLong(100, 1L..2L) → all 1L and randomInt(100, 1..2) → both values.

Problem 2: columnOf's reified argument is an upper bound, not the column type

  • Problem: columnOf<Number>(1, 2) produces a column of type Int, not Number — the type is
    inferred from the values within the bound; Number only results from mixed values
    (columnOf<Number>(1, 2.5)).
  • Options: document the inference-with-bound semantics; or make columnOf use T as declared —
    that would change behaviour and duplicate column(Iterable), which already does exactly that.
  • Chosen: the KDoc states the upper-bound semantics with both examples.
  • Test: columnOf infers a narrower type from homogeneous values (Int),
    columnOf of mixed values has the upper bound type (Number).

Problem 3: empty header always throws

  • Problem: dataFrameOf(emptyList<String>(), emptyList()) throws
    IllegalArgumentException ("Number of values 0 is not divisible by number of columns 0"), while a
    non-empty header with zero values creates a 0-row frame.
  • Options: return an empty frame for the empty header; or document and pin.
  • Chosen: documented on DataFrameBuilder.invoke and pinned; behaviour unchanged.
  • Test: dataFrameOf with empty header throws even without values.

Problem 4: the empty path has no name

  • Problem: ColumnPath.EMPTY.name() throws NoSuchElementException ("List is empty").
  • Options: a guard returning null (a public behaviour change); or document and pin.
  • Chosen: documented on pathOf and in the Column Resolvers section; behaviour unchanged.
  • Test: empty path has no name.

Tests

Before, ConstructorsTests covered ~12 scenarios; the accessor families, most dataFrameOf overloads
and all DataFrameBuilder members were untested. Expected values come from probe runs; static types are
asserted with explicit type annotations.

Tests What they pin down
ColumnAccessorsTests (14) delegate names and @ColumnName overrides, access by name/path, typed and untyped overloads, nesting via a receiver, named, the computed reference in select/add/update, the deprecated KProperty overload
columnOf/column (10) upper-bound type inference, lists stay value columns, a collection among values widens to Any?, declared type of column(Iterable), empty column, column groups and frame columns
dataFrameOf (14) duplicate names and unequal sizes (incl. the pairs-of-lists overload), "untitled" generation with no clash against a literal untitled, row-major fill, indivisible values and the empty header with exact messages, header variants, deprecated-overload equivalence
DataFrameBuilder (8) column-count check, rename to header, fill/nulls nullability, random* types and bounds, Sequence invoke, per-column inference
emptyDataFrame/pathOf (6) Unit → 0×0, a class without @DataSchema gets columns from properties, vs DataFrame.empty; empty path, last-segment name
KDoc example … (2), samples (7) every literal KDoc/page example is asserted (the dataFrameOf pairs example was unbacked before)

Note for the reviewer

Beyond the ticket

  • The website pages are updated too: the new KDoc links point at createcolumn.html,
    createdataframe.html and columnselectors.html, and those pages had no sections describing the
    documented APIs.

Conventions

Open question

  • randomLong/randomDouble treat ClosedRange.endInclusive as excluded while randomInt(IntRange)
    includes both bounds. Should the ClosedRange overloads include the upper bound for symmetry?
    Not changed in this PR.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for this thorough work! One blocking doc inaccuracy needs fixing before merge.

Produced by Air Automations. Name: AI Review / Run: https://air.jetbrains.cloud/org/05cf1a7f-6ab5-713b-abd3-29d0c8a05e2d/automations/8daf2412-0b6c-4433-90c0-b40ab5aebcdb?run=a4821ed4-d9f7-4e51-8ae2-83dad7a9e897


/**
* Creates a [DataFrame] where the values of each column are produced by [valuesBuilder]
* for that column's name; the column type comes from [T].

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Blocking: "the column type comes from [T]" is wrong — the implementation uses TypeSuggestion.InferWithUpperbound(typeOf<T>()), the same upper-bound semantics this PR documents for columnOf (Problem 2).

Failure: dataFrameOf("a").invoke<Number> { listOf(1, 2) } yields an Int column, not Number. The top-level dataFrameOf(vararg header, fill) delegates here, and dataFrameOf(header: Iterable<T>, fill) behaves identically, so both inherit the gap.

Fix: say the type is inferred from the values with [T] as an upper bound (reuse the columnOf wording, ideally as a shared ConstructorsDocs fragment), apply it to both fill-lambda dataFrameOf overloads too, and pin it with a test.

@TransformDataFrameExpressions
fun createComputedColumnReference_strings() {
// SampleStart
val isAdult = column<Boolean>("isAdult") { "age"<Int>() > 18 }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The new _strings website sample uses the Invoked String API ("age"<Int>()). DOCUMENTATION_GUIDELINES.md and the operation-website-documentation skill ban it explicitly as outdated.

Failure: the createColumn page now teaches the not-recommended style in a tab meant to show the String API.

Fix: column<Boolean>("isAdult") { getValue<Int>("age") > 18 }. Using the same df as the _properties tab would also keep the two tabs equivalent.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve test coverage for constructors.kt Add KDocs for constructors.kt

1 participant