Skip to content

Commit 5a19da6

Browse files
committed
Add support for different IDE versions in DataFrame rendering
This update introduces specific rendering flows based on the version of the IDE. A new method has been added to retrieve the IDE build number. This information is then used to conditionally generate a JSON-encoded DataFrame, adapting to the specific capabilities of the IDE version in use. Additionally, relevant tests have been updated to accommodate these changes.
1 parent 240181d commit 5a19da6

File tree

6 files changed

+134
-2
lines changed

6 files changed

+134
-2
lines changed

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/JupyterHtmlRenderer.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package org.jetbrains.kotlinx.dataframe.jupyter
22

3+
import com.beust.klaxon.json
4+
import org.jetbrains.kotlinx.dataframe.api.rows
5+
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
36
import org.jetbrains.kotlinx.dataframe.io.DataFrameHtmlData
47
import org.jetbrains.kotlinx.dataframe.io.DisplayConfiguration
8+
import org.jetbrains.kotlinx.dataframe.io.encodeFrame
59
import org.jetbrains.kotlinx.dataframe.io.toHTML
610
import org.jetbrains.kotlinx.dataframe.io.toJsonWithMetadata
711
import org.jetbrains.kotlinx.dataframe.io.toStaticHtml
812
import org.jetbrains.kotlinx.dataframe.jupyter.KotlinNotebookPluginUtils.convertToDataFrame
913
import org.jetbrains.kotlinx.dataframe.nrow
14+
import org.jetbrains.kotlinx.dataframe.size
1015
import org.jetbrains.kotlinx.jupyter.api.HtmlData
1116
import org.jetbrains.kotlinx.jupyter.api.JupyterClientType
1217
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelVersion
@@ -18,6 +23,7 @@ import org.jetbrains.kotlinx.jupyter.api.renderHtmlAsIFrameIfNeeded
1823

1924
/** Starting from this version, dataframe integration will respond with additional data for rendering in Kotlin Notebooks plugin. */
2025
private const val MIN_KERNEL_VERSION_FOR_NEW_TABLES_UI = "0.11.0.311"
26+
private const val MIN_IDE_VERSION_SUPPORT_JSON_WITH_METADATA = 241
2127

2228
internal class JupyterHtmlRenderer(
2329
val display: DisplayConfiguration,
@@ -56,7 +62,21 @@ internal inline fun <reified T : Any> JupyterHtmlRenderer.render(
5662
val staticHtml = df.toStaticHtml(reifiedDisplayConfiguration, DefaultCellRenderer).toJupyterHtmlData()
5763

5864
if (notebook.kernelVersion >= KotlinKernelVersion.from(MIN_KERNEL_VERSION_FOR_NEW_TABLES_UI)!!) {
59-
val jsonEncodedDf = df.toJsonWithMetadata(limit, reifiedDisplayConfiguration.rowsLimit)
65+
val ideBuildNumber = KotlinNotebookPluginUtils.getKotlinNotebookIDEBuildNumber()
66+
67+
val jsonEncodedDf =
68+
if (ideBuildNumber == null || ideBuildNumber.majorVersion < MIN_IDE_VERSION_SUPPORT_JSON_WITH_METADATA) {
69+
json {
70+
obj(
71+
"nrow" to df.size.nrow,
72+
"ncol" to df.size.ncol,
73+
"columns" to df.columnNames(),
74+
"kotlin_dataframe" to encodeFrame(df.rows().take(limit).toDataFrame()),
75+
)
76+
}
77+
} else {
78+
df.toJsonWithMetadata(limit, reifiedDisplayConfiguration.rowsLimit)
79+
}
6080
notebook.renderAsIFrameAsNeeded(html, staticHtml, jsonEncodedDf.toJsonString())
6181
} else {
6282
notebook.renderHtmlAsIFrameIfNeeded(html)

core/generated-sources/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/KotlinNotebookPluginUtils.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import org.jetbrains.kotlinx.dataframe.impl.ColumnNameGenerator
4141
* DISPLAY(KotlinNotebooksPluginUtils.getRowsSubsetForRendering(Out[...], 0, 20), "")
4242
*/
4343
public object KotlinNotebookPluginUtils {
44+
private const val KTNB_IDE_BUILD_PROP = "KTNB_IDE_BUILD_NUMBER"
45+
4446
/**
4547
* Returns a subset of rows from the given dataframe for rendering.
4648
* It's used for example for dynamic pagination in Kotlin Notebook Plugin.
@@ -166,4 +168,36 @@ public object KotlinNotebookPluginUtils {
166168
usedNames: List<String> = emptyList()
167169
): String =
168170
ColumnNameGenerator(usedNames).addUnique(preferredName)
171+
172+
/**
173+
* Retrieves the build number of the Kotlin Notebook IDE.
174+
*
175+
* @return The build number of the Kotlin Notebook IDE as an instance of [IdeBuildNumber],
176+
* or null if the build number is not available.
177+
*/
178+
public fun getKotlinNotebookIDEBuildNumber(): IdeBuildNumber? {
179+
val value = System.getProperty(KTNB_IDE_BUILD_PROP, null) ?: return null
180+
return IdeBuildNumber.fromString(value)
181+
}
182+
183+
public data class IdeBuildNumber(val ideName: String, val majorVersion: Int, val buildId: Int) {
184+
public companion object {
185+
public fun fromString(buildNumber: String): IdeBuildNumber? {
186+
val parts = buildNumber.split(";")
187+
return if (parts.size == 3) constructIdeBuildNumber(parts) else null
188+
}
189+
190+
private fun constructIdeBuildNumber(parts: List<String>): IdeBuildNumber? {
191+
val ideName = parts[0]
192+
val majorVersion = parts[1].toIntOrNull()
193+
val buildId = parts[2].toIntOrNull()
194+
195+
return if (majorVersion != null && buildId != null) {
196+
IdeBuildNumber(ideName, majorVersion, buildId)
197+
} else {
198+
null
199+
}
200+
}
201+
}
202+
}
169203
}

core/generated-sources/src/test/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/RenderingTests.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import org.jetbrains.kotlinx.dataframe.io.SerializationKeys.KOTLIN_DATAFRAME
1515
import org.jetbrains.kotlinx.dataframe.io.SerializationKeys.METADATA
1616
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
1717
import org.jetbrains.kotlinx.jupyter.testkit.JupyterReplTestCase
18+
import org.junit.BeforeClass
1819
import org.junit.Test
1920

2021
class RenderingTests : JupyterReplTestCase() {
@@ -243,4 +244,15 @@ class RenderingTests : JupyterReplTestCase() {
243244
assertDataFrameDimensions(json, 2, 2)
244245
}
245246
}
247+
248+
companion object {
249+
/**
250+
* Set the system property for the IDE version needed for specific serialization testing purposes.
251+
*/
252+
@BeforeClass
253+
@JvmStatic
254+
internal fun setupOnce() {
255+
System.setProperty("KTNB_IDE_BUILD_NUMBER", "IU;241;14015")
256+
}
257+
}
246258
}

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/JupyterHtmlRenderer.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
package org.jetbrains.kotlinx.dataframe.jupyter
22

3+
import com.beust.klaxon.json
4+
import org.jetbrains.kotlinx.dataframe.api.rows
5+
import org.jetbrains.kotlinx.dataframe.api.toDataFrame
36
import org.jetbrains.kotlinx.dataframe.io.DataFrameHtmlData
47
import org.jetbrains.kotlinx.dataframe.io.DisplayConfiguration
8+
import org.jetbrains.kotlinx.dataframe.io.encodeFrame
59
import org.jetbrains.kotlinx.dataframe.io.toHTML
610
import org.jetbrains.kotlinx.dataframe.io.toJsonWithMetadata
711
import org.jetbrains.kotlinx.dataframe.io.toStaticHtml
812
import org.jetbrains.kotlinx.dataframe.jupyter.KotlinNotebookPluginUtils.convertToDataFrame
913
import org.jetbrains.kotlinx.dataframe.nrow
14+
import org.jetbrains.kotlinx.dataframe.size
1015
import org.jetbrains.kotlinx.jupyter.api.HtmlData
1116
import org.jetbrains.kotlinx.jupyter.api.JupyterClientType
1217
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelVersion
@@ -18,6 +23,7 @@ import org.jetbrains.kotlinx.jupyter.api.renderHtmlAsIFrameIfNeeded
1823

1924
/** Starting from this version, dataframe integration will respond with additional data for rendering in Kotlin Notebooks plugin. */
2025
private const val MIN_KERNEL_VERSION_FOR_NEW_TABLES_UI = "0.11.0.311"
26+
private const val MIN_IDE_VERSION_SUPPORT_JSON_WITH_METADATA = 241
2127

2228
internal class JupyterHtmlRenderer(
2329
val display: DisplayConfiguration,
@@ -56,7 +62,21 @@ internal inline fun <reified T : Any> JupyterHtmlRenderer.render(
5662
val staticHtml = df.toStaticHtml(reifiedDisplayConfiguration, DefaultCellRenderer).toJupyterHtmlData()
5763

5864
if (notebook.kernelVersion >= KotlinKernelVersion.from(MIN_KERNEL_VERSION_FOR_NEW_TABLES_UI)!!) {
59-
val jsonEncodedDf = df.toJsonWithMetadata(limit, reifiedDisplayConfiguration.rowsLimit)
65+
val ideBuildNumber = KotlinNotebookPluginUtils.getKotlinNotebookIDEBuildNumber()
66+
67+
val jsonEncodedDf =
68+
if (ideBuildNumber == null || ideBuildNumber.majorVersion < MIN_IDE_VERSION_SUPPORT_JSON_WITH_METADATA) {
69+
json {
70+
obj(
71+
"nrow" to df.size.nrow,
72+
"ncol" to df.size.ncol,
73+
"columns" to df.columnNames(),
74+
"kotlin_dataframe" to encodeFrame(df.rows().take(limit).toDataFrame()),
75+
)
76+
}
77+
} else {
78+
df.toJsonWithMetadata(limit, reifiedDisplayConfiguration.rowsLimit)
79+
}
6080
notebook.renderAsIFrameAsNeeded(html, staticHtml, jsonEncodedDf.toJsonString())
6181
} else {
6282
notebook.renderHtmlAsIFrameIfNeeded(html)

core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/KotlinNotebookPluginUtils.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ import org.jetbrains.kotlinx.dataframe.impl.ColumnNameGenerator
4141
* DISPLAY(KotlinNotebooksPluginUtils.getRowsSubsetForRendering(Out[...], 0, 20), "")
4242
*/
4343
public object KotlinNotebookPluginUtils {
44+
private const val KTNB_IDE_BUILD_PROP = "KTNB_IDE_BUILD_NUMBER"
45+
4446
/**
4547
* Returns a subset of rows from the given dataframe for rendering.
4648
* It's used for example for dynamic pagination in Kotlin Notebook Plugin.
@@ -166,4 +168,36 @@ public object KotlinNotebookPluginUtils {
166168
usedNames: List<String> = emptyList()
167169
): String =
168170
ColumnNameGenerator(usedNames).addUnique(preferredName)
171+
172+
/**
173+
* Retrieves the build number of the Kotlin Notebook IDE.
174+
*
175+
* @return The build number of the Kotlin Notebook IDE as an instance of [IdeBuildNumber],
176+
* or null if the build number is not available.
177+
*/
178+
public fun getKotlinNotebookIDEBuildNumber(): IdeBuildNumber? {
179+
val value = System.getProperty(KTNB_IDE_BUILD_PROP, null) ?: return null
180+
return IdeBuildNumber.fromString(value)
181+
}
182+
183+
public data class IdeBuildNumber(val ideName: String, val majorVersion: Int, val buildId: Int) {
184+
public companion object {
185+
public fun fromString(buildNumber: String): IdeBuildNumber? {
186+
val parts = buildNumber.split(";")
187+
return if (parts.size == 3) constructIdeBuildNumber(parts) else null
188+
}
189+
190+
private fun constructIdeBuildNumber(parts: List<String>): IdeBuildNumber? {
191+
val ideName = parts[0]
192+
val majorVersion = parts[1].toIntOrNull()
193+
val buildId = parts[2].toIntOrNull()
194+
195+
return if (majorVersion != null && buildId != null) {
196+
IdeBuildNumber(ideName, majorVersion, buildId)
197+
} else {
198+
null
199+
}
200+
}
201+
}
202+
}
169203
}

core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/jupyter/RenderingTests.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import org.jetbrains.kotlinx.dataframe.io.SerializationKeys.KOTLIN_DATAFRAME
1515
import org.jetbrains.kotlinx.dataframe.io.SerializationKeys.METADATA
1616
import org.jetbrains.kotlinx.jupyter.api.MimeTypedResult
1717
import org.jetbrains.kotlinx.jupyter.testkit.JupyterReplTestCase
18+
import org.junit.BeforeClass
1819
import org.junit.Test
1920

2021
class RenderingTests : JupyterReplTestCase() {
@@ -243,4 +244,15 @@ class RenderingTests : JupyterReplTestCase() {
243244
assertDataFrameDimensions(json, 2, 2)
244245
}
245246
}
247+
248+
companion object {
249+
/**
250+
* Set the system property for the IDE version needed for specific serialization testing purposes.
251+
*/
252+
@BeforeClass
253+
@JvmStatic
254+
internal fun setupOnce() {
255+
System.setProperty("KTNB_IDE_BUILD_NUMBER", "IU;241;14015")
256+
}
257+
}
246258
}

0 commit comments

Comments
 (0)