diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 767fef0490..e7e57cf3a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,8 +52,8 @@ so do familiarize yourself with the following guidelines. ## PR workflow -0. The contributor builds the library locally and runs all unit tests via the Gradle task `dataframe:test` - (see the ["Building"](#building) chapter). +0. The contributor builds the library locally and runs all unit tests via the Gradle task + `dataframe:test -Pkotlin.dataframe.debug=true` (see the ["Building"](#building) chapter). 1. The contributor submits the PR if the local build is successful and the tests are green. 2. The reviewer puts their name in the "Reviewers" section of the proposed PR at the start of the review process. 3. The reviewer leaves comments or marks the PR with the abbreviation "LGTM" (Looks good to me). @@ -103,6 +103,8 @@ This library is built with Gradle. * Run `./gradlew build` to build. It also runs all the tests and checks the linter. * Run `./gradlew :test` to test the module you are looking at to speed things up during development. +* Make sure to pass the extra parameter `-Pkotlin.dataframe.debug=true` to enable debug mode. This flag will + make sure some extra checks are run, which are important but too heavy for production. You can import this project into IDEA, but you have to delegate the build actions to Gradle (in Preferences -> Build, Execution, Deployment -> Build Tools -> Gradle -> Runner) diff --git a/build.gradle.kts b/build.gradle.kts index 6c4ad837d3..fa78e51e24 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -163,6 +163,7 @@ allprojects { packageName = "org.jetbrains.kotlinx.dataframe" className = "BuildConfig" buildConfigField("VERSION", "${project.version}") + buildConfigField("DEBUG", findProperty("kotlin.dataframe.debug")?.toString()?.toBoolean() ?: false) } } catch (_: UnknownDomainObjectException) { logger.warn("Could not set buildConfig on :${this.name}") diff --git a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/DataColumnImpl.kt b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/DataColumnImpl.kt index cce956c1c4..c7ef55c5a5 100644 --- a/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/DataColumnImpl.kt +++ b/core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/DataColumnImpl.kt @@ -1,8 +1,13 @@ package org.jetbrains.kotlinx.dataframe.impl.columns +import org.jetbrains.kotlinx.dataframe.BuildConfig import org.jetbrains.kotlinx.dataframe.DataColumn import org.jetbrains.kotlinx.dataframe.api.dataFrameOf +import org.jetbrains.kotlinx.dataframe.impl.isArray +import org.jetbrains.kotlinx.dataframe.impl.isPrimitiveArray +import kotlin.reflect.KClass import kotlin.reflect.KType +import kotlin.reflect.full.isSubclassOf internal abstract class DataColumnImpl( protected val values: List, @@ -12,6 +17,32 @@ internal abstract class DataColumnImpl( ) : DataColumn, DataColumnInternal { + private infix fun T?.matches(type: KType) = + when { + this == null -> type.isMarkedNullable + + this.isPrimitiveArray -> + type.isPrimitiveArray && + this!!::class.qualifiedName == type.classifier?.let { (it as KClass<*>).qualifiedName } + + this.isArray -> type.isArray + + // cannot check the precise type of array + else -> this!!::class.isSubclassOf(type.classifier as KClass<*>) + } + + init { + /* Check for [Issue #713](https://github.com/Kotlin/dataframe/issues/713). + * This only runs with `kotlin.dataframe.debug=true` in gradle.properties + */ + if (BuildConfig.DEBUG) { + require(values.all { it matches type }) { + val types = values.map { if (it == null) "Nothing?" else it!!::class.simpleName }.distinct() + "Values of column '$name' have types '$types' which are not compatible given with column type '$type'" + } + } + } + protected val distinct = distinct ?: lazy { values.toSet() } override fun name() = name diff --git a/gradle.properties b/gradle.properties index faf44dfd03..6fcbca9f35 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,3 +11,8 @@ org.gradle.jvmargs=-Xmx4G # This makes it mandatory to explicitly apply your own version of the # KSP plugin in the modules that use it. kotlin.dataframe.add.ksp=false + +# Enables debug mode for dataframe. +# This can make certain tests run that should not be run in production. +# It can also be turned on from the command line with `-Pkotlin.dataframe.debug=true` +kotlin.dataframe.debug=false