Skip to content

Commit

Permalink
Allow value rendering using renderers processor from API
Browse files Browse the repository at this point in the history
  • Loading branch information
ileasile committed Apr 6, 2021
1 parent 8e3677d commit 343c93d
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,10 @@ interface Notebook {
* Current JRE info
*/
val jreInfo: JREInfoProvider

/**
* Renderers processor gives an ability to render values and
* and add new renderers
*/
val renderersProcessor: TypeRenderersProcessor
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.jetbrains.kotlinx.jupyter.api

import org.jetbrains.kotlinx.jupyter.api.libraries.ExecutionHost

/**
* [TypeRenderersProcessor] is responsible for rendering objects.
* You may use it to render values exactly like notebook renders results,
* and also register new renderers in runtime.
*/
interface TypeRenderersProcessor {
/**
* Renders [value] in context of this execution [host]
*/
fun renderValue(host: ExecutionHost, value: Any?): Any?

/**
* Adds new [renderer] for this notebook.
* Don't turn on the optimizations for [PrecompiledRendererTypeHandler]
*/
fun registerWithoutOptimizing(renderer: RendererTypeHandler)
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ abstract class JupyterIntegration : LibraryDefinitionProducer {
}

inline fun <reified T : Any> render(noinline renderer: CodeCell.(T) -> Any) {
val execution = ResultHandlerExecution { _, property ->
return renderWithHost { _, value: T -> renderer(this, value) }
}

inline fun <reified T : Any> renderWithHost(noinline renderer: CodeCell.(ExecutionHost, T) -> Any) {
val execution = ResultHandlerExecution { host, property ->
val currentCell = notebook.currentCell
?: throw IllegalStateException("Current cell should not be null on renderer invocation")
FieldValue(renderer(currentCell, property.value as T), property.name)
FieldValue(renderer(currentCell, host, property.value as T), property.name)
}
addRenderer(SubtypeRendererTypeHandler(T::class, execution))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.jetbrains.kotlinx.jupyter.codegen

import org.jetbrains.kotlinx.jupyter.api.Code
import org.jetbrains.kotlinx.jupyter.api.FieldValue
import org.jetbrains.kotlinx.jupyter.api.PrecompiledRendererTypeHandler
import org.jetbrains.kotlinx.jupyter.api.RendererTypeHandler
import org.jetbrains.kotlinx.jupyter.api.TypeRenderersProcessor
import org.jetbrains.kotlinx.jupyter.api.libraries.ExecutionHost

interface ResultsTypeRenderersProcessor : TypeRenderersProcessor {
/**
* Renders cell result [field] represented as [FieldValue] in the [host] context
*/
fun renderResult(host: ExecutionHost, field: FieldValue): Any?

/**
* Adds new [renderer] for this notebook.
* Returns code to be executed on execution host
* for [PrecompiledRendererTypeHandler]'s.
*/
fun register(renderer: RendererTypeHandler): Code?
}

This file was deleted.

5 changes: 5 additions & 0 deletions src/main/kotlin/org/jetbrains/kotlinx/jupyter/apiImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.jetbrains.kotlinx.jupyter.api.DisplayResultWithCell
import org.jetbrains.kotlinx.jupyter.api.JREInfoProvider
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelVersion
import org.jetbrains.kotlinx.jupyter.api.Notebook
import org.jetbrains.kotlinx.jupyter.api.TypeRenderersProcessor
import java.lang.IllegalStateException

class DisplayResultWrapper private constructor(
Expand Down Expand Up @@ -98,6 +99,7 @@ class NotebookImpl(
private val runtimeProperties: ReplRuntimeProperties,
) : Notebook {
private val cells = hashMapOf<Int, CodeCellImpl>()
internal var typeRenderersProcessor: TypeRenderersProcessor? = null

override val cellsList: Collection<CodeCellImpl>
get() = cells.values
Expand Down Expand Up @@ -156,4 +158,7 @@ class NotebookImpl(

override val lastCell: CodeCellImpl?
get() = history(1)

override val renderersProcessor: TypeRenderersProcessor
get() = typeRenderersProcessor ?: throw IllegalStateException("Type renderers processor is not initialized yet")
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import org.jetbrains.kotlinx.jupyter.repl.ContextUpdater

class TypeRenderersProcessorImpl(
private val contextUpdater: ContextUpdater,
) : TypeRenderersProcessor {
) : ResultsTypeRenderersProcessor {
private var counter = 0
private val typeRenderers: MutableList<HandlerWithInfo> = mutableListOf()

Expand All @@ -35,8 +35,20 @@ class TypeRenderersProcessorImpl(
}
}

override fun renderValue(host: ExecutionHost, value: Any?): Any? {
return renderResult(host, FieldValue(value, null))
}

override fun register(renderer: RendererTypeHandler): Code? {
if (renderer !is PrecompiledRendererTypeHandler || !renderer.mayBePrecompiled) {
return register(renderer, true)
}

override fun registerWithoutOptimizing(renderer: RendererTypeHandler) {
register(renderer, false)
}

private fun register(renderer: RendererTypeHandler, doOptimization: Boolean): Code? {
if (!doOptimization || renderer !is PrecompiledRendererTypeHandler || !renderer.mayBePrecompiled) {
typeRenderers.add(HandlerWithInfo(renderer, null))
return null
}
Expand Down
12 changes: 8 additions & 4 deletions src/main/kotlin/org/jetbrains/kotlinx/jupyter/repl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import org.jetbrains.kotlinx.jupyter.codegen.FieldsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.FieldsProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.FileAnnotationsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.FileAnnotationsProcessorImpl
import org.jetbrains.kotlinx.jupyter.codegen.TypeRenderersProcessor
import org.jetbrains.kotlinx.jupyter.codegen.ResultsTypeRenderersProcessor
import org.jetbrains.kotlinx.jupyter.codegen.TypeRenderersProcessorImpl
import org.jetbrains.kotlinx.jupyter.common.looksLikeReplCommand
import org.jetbrains.kotlinx.jupyter.compiler.CompilerArgsConfigurator
Expand Down Expand Up @@ -307,7 +307,11 @@ class ReplForJupyterImpl(
executedCodeLogging != ExecutedCodeLogging.Off
)

private val typeRenderersProcessor: TypeRenderersProcessor = TypeRenderersProcessorImpl(contextUpdater)
private val typeRenderersProcessor: ResultsTypeRenderersProcessor = run {
val processor = TypeRenderersProcessorImpl(contextUpdater)
notebook.typeRenderersProcessor = processor
processor
}

private val fieldsProcessor: FieldsProcessor = FieldsProcessorImpl(contextUpdater)

Expand Down Expand Up @@ -421,11 +425,11 @@ class ReplForJupyterImpl(
currentClasspath.addAll(newClasspath)
if (trackClasspath) {
val sb = StringBuilder()
if (newClasspath.count() > 0) {
if (newClasspath.isNotEmpty()) {
sb.appendLine("${newClasspath.count()} new paths were added to classpath:")
newClasspath.sortedBy { it }.forEach { sb.appendLine(it) }
}
if (oldClasspath.count() > 0) {
if (oldClasspath.isNotEmpty()) {
sb.appendLine("${oldClasspath.count()} resolved paths were already in classpath:")
oldClasspath.sortedBy { it }.forEach { sb.appendLine(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.jetbrains.kotlinx.jupyter.api.Notebook
import org.jetbrains.kotlinx.jupyter.codegen.ClassAnnotationsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.FieldsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.FileAnnotationsProcessor
import org.jetbrains.kotlinx.jupyter.codegen.TypeRenderersProcessor
import org.jetbrains.kotlinx.jupyter.codegen.ResultsTypeRenderersProcessor
import org.jetbrains.kotlinx.jupyter.libraries.LibrariesScanner
import org.jetbrains.kotlinx.jupyter.libraries.LibraryResourcesProcessor
import org.jetbrains.kotlinx.jupyter.magics.MagicsProcessor
Expand All @@ -16,7 +16,7 @@ internal data class SharedReplContext(
val classAnnotationsProcessor: ClassAnnotationsProcessor,
val fileAnnotationsProcessor: FileAnnotationsProcessor,
val fieldsProcessor: FieldsProcessor,
val typeRenderersProcessor: TypeRenderersProcessor,
val typeRenderersProcessor: ResultsTypeRenderersProcessor,
val magicsProcessor: MagicsProcessor,
val resourcesProcessor: LibraryResourcesProcessor,
val librariesScanner: LibrariesScanner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,23 @@ class IntegrationApiTests {
assertEquals("1. 420", repl.eval("42.1").resultValue)
assertEquals("2. 150", repl.eval("15").resultValue)
}

@Test
fun `rendering processor should work fine`() {
val repl = makeRepl()
repl.eval(
"""
class A
class B(val a: A)
USE {
render<A> { "iA" }
renderWithHost<B> { host, value -> "iB: " + notebook!!.renderersProcessor.renderValue(host, value.a) }
}
""".trimIndent()
)

val result = repl.eval("B(A())")
assertEquals("iB: iA", result.resultValue)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.jetbrains.kotlinx.jupyter.api.DisplayResultWithCell
import org.jetbrains.kotlinx.jupyter.api.JREInfoProvider
import org.jetbrains.kotlinx.jupyter.api.KotlinKernelVersion
import org.jetbrains.kotlinx.jupyter.api.Notebook
import org.jetbrains.kotlinx.jupyter.api.TypeRenderersProcessor
import org.jetbrains.kotlinx.jupyter.api.libraries.JupyterIntegration
import org.jetbrains.kotlinx.jupyter.api.libraries.LibraryDefinition
import org.jetbrains.kotlinx.jupyter.config.defaultRepositories
Expand Down Expand Up @@ -59,7 +60,7 @@ fun assertStartsWith(expectedPrefix: String, actual: String) {
}

fun Collection<Pair<String, String>>.toLibraries(): LibraryResolver {
val libJsons = map { it.first to it.second }.toMap()
val libJsons = associate { it.first to it.second }
return getResolverFromNamesMap(parseLibraryDescriptors(libJsons))
}

Expand Down Expand Up @@ -163,6 +164,9 @@ object NotebookMock : Notebook {
get() = defaultRuntimeProperties.version!!
override val jreInfo: JREInfoProvider
get() = JavaRuntime

override val renderersProcessor: TypeRenderersProcessor
get() = error("Not supposed to be called")
}

fun library(builder: JupyterIntegration.Builder.() -> Unit): LibraryDefinition {
Expand Down

0 comments on commit 343c93d

Please sign in to comment.