Skip to content

Commit 8eea146

Browse files
Get unchangedVariables from notebook to reflect after execution state properly
1 parent 4541088 commit 8eea146

File tree

7 files changed

+91
-7
lines changed

7 files changed

+91
-7
lines changed

src/main/kotlin/org/jetbrains/kotlinx/jupyter/apiImpl.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class NotebookImpl(
123123
private var currentCellVariables = mapOf<Int, Set<String>>()
124124
private val history = arrayListOf<CodeCellImpl>()
125125
private var mainCellCreated = false
126+
private val unchangedVariables: MutableSet<String> = mutableSetOf()
126127

127128
val displays = DisplayContainerImpl()
128129

@@ -142,12 +143,16 @@ class NotebookImpl(
142143
fun updateVariablesState(evaluator: InternalEvaluator) {
143144
variablesState += evaluator.variablesHolder
144145
currentCellVariables = evaluator.cellVariables
146+
unchangedVariables.clear()
147+
unchangedVariables.addAll(evaluator.getUnchangedVariables())
145148
}
146149

147150
fun updateVariablesState(varsStateUpdate: Map<String, VariableState>) {
148151
variablesState += varsStateUpdate
149152
}
150153

154+
fun unchangedVariables(): Set<String> = unchangedVariables
155+
151156
fun variablesReportAsHTML(): String {
152157
return generateHTMLVarsReport(variablesState)
153158
}

src/main/kotlin/org/jetbrains/kotlinx/jupyter/repl/InternalEvaluator.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ interface InternalEvaluator {
3232
fun popAddedCompiledScripts(): SerializedCompiledScriptsData = SerializedCompiledScriptsData.EMPTY
3333

3434
/**
35-
* Get a cellId where particular variable is declared
35+
* Get a cellId where a particular variable is declared
3636
*/
3737
fun findVariableCell(variableName: String): Int
38+
39+
/**
40+
* Returns a set of unaffected variables after execution
41+
*/
42+
fun getUnchangedVariables(): Set<String>
3843
}

src/main/kotlin/org/jetbrains/kotlinx/jupyter/repl/impl/InternalEvaluatorImpl.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ internal class InternalEvaluatorImpl(
5252
return variablesWatcher.findDeclarationAddress(variableName) ?: -1
5353
}
5454

55+
override fun getUnchangedVariables(): Set<String> {
56+
return variablesWatcher.getUnchangedVariables()
57+
}
58+
5559
override var writeCompiledClasses: Boolean
5660
get() = classWriter != null
5761
set(value) {
@@ -170,7 +174,6 @@ internal class InternalEvaluatorImpl(
170174
}.toHashSet()
171175
val ans = mutableMapOf<String, VariableStateImpl>()
172176
fields.forEach { property ->
173-
// if (property.name.startsWith("script$")) return@forEach
174177
if (!memberKPropertiesNames.contains(property.name)) return@forEach
175178

176179
val state = VariableStateImpl(property, cellClassInstance)

src/main/kotlin/org/jetbrains/kotlinx/jupyter/serializationUtils.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,11 @@ class VariablesSerializer(private val serializationDepth: Int = 2, private val s
110110
} == true
111111
}
112112

113-
val kProperties = if (value != null) value::class.declaredMemberProperties else {
114-
null
115-
}
113+
val kProperties = try {
114+
if (value != null) value::class.declaredMemberProperties else {
115+
null
116+
}
117+
} catch (ex: Exception) {null}
116118
val serializedVersion = SerializedVariablesState(simpleTypeName, getProperString(value), true)
117119
val descriptors = serializedVersion.fieldDescriptor
118120
if (isDescriptorsNeeded) {
@@ -214,6 +216,11 @@ class VariablesSerializer(private val serializationDepth: Int = 2, private val s
214216

215217
private val isSerializationActive: Boolean = System.getProperty(serializationSystemProperty)?.toBooleanStrictOrNull() ?: true
216218

219+
/**
220+
* Cache for not recomputing unchanged variables
221+
*/
222+
val serializedVariablesCache: MutableMap<String, SerializedVariablesState> = mutableMapOf()
223+
217224
fun serializeVariables(cellId: Int, variablesState: Map<String, VariableState>): Map<String, SerializedVariablesState> {
218225
if (!isSerializationActive) return emptyMap()
219226

src/main/kotlin/org/jetbrains/kotlinx/jupyter/util.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ class VariablesUsagesPerCellWatcher<K : Any, V : Any> {
8383
*/
8484
private val variablesDeclarationInfo: MutableMap<V, K> = mutableMapOf()
8585

86+
private val unchangedVariables: MutableSet<V> = mutableSetOf()
87+
// private val unchangedVariables: MutableSet<V> = mutableSetOf()
88+
8689
fun addDeclaration(address: K, variableRef: V) {
8790
ensureStorageCreation(address)
8891

@@ -91,21 +94,35 @@ class VariablesUsagesPerCellWatcher<K : Any, V : Any> {
9194
val oldCellId = variablesDeclarationInfo[variableRef]
9295
if (oldCellId != address) {
9396
cellVariables[oldCellId]?.remove(variableRef)
97+
unchangedVariables.remove(variableRef)
9498
}
99+
} else {
100+
unchangedVariables.add(variableRef)
95101
}
96102
variablesDeclarationInfo[variableRef] = address
97103
cellVariables[address]?.add(variableRef)
98104
}
99105

100-
fun addUsage(address: K, variableRef: V) = cellVariables[address]?.add(variableRef)
106+
fun addUsage(address: K, variableRef: V) {
107+
cellVariables[address]?.add(variableRef)
108+
if (variablesDeclarationInfo[variableRef] != address) {
109+
unchangedVariables.remove(variableRef)
110+
}
111+
}
101112

102113
fun removeOldUsages(newAddress: K) {
103114
// remove known modifying usages in this cell
104115
cellVariables[newAddress]?.removeIf {
105-
variablesDeclarationInfo[it] != newAddress
116+
val predicate = variablesDeclarationInfo[it] != newAddress
117+
if (predicate) {
118+
unchangedVariables.add(it)
119+
}
120+
predicate
106121
}
107122
}
108123

124+
fun getUnchangedVariables(): Set<V> = unchangedVariables
125+
109126
fun findDeclarationAddress(variableRef: V) = variablesDeclarationInfo[variableRef]
110127

111128
fun ensureStorageCreation(address: K) = cellVariables.putIfAbsent(address, mutableSetOf())

src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl/ReplTests.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import kotlin.script.experimental.api.SourceCode
2323
import kotlin.test.assertEquals
2424
import kotlin.test.assertFails
2525
import kotlin.test.assertFalse
26+
import kotlin.test.assertNotEquals
2627
import kotlin.test.fail
2728

2829
class ReplTests : AbstractSingleReplTest() {
@@ -1011,4 +1012,43 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
10111012
}
10121013
}
10131014
}
1015+
1016+
1017+
@Test
1018+
fun testUnchangedVariables() {
1019+
eval(
1020+
"""
1021+
private val x = "abcd"
1022+
var f = 47
1023+
internal val z = 47
1024+
""".trimIndent(),
1025+
jupyterId = 1
1026+
)
1027+
val state = repl.notebook.unchangedVariables()
1028+
val setOfCell = setOf("x", "f", "z")
1029+
assertTrue(state.isNotEmpty())
1030+
assertEquals(setOfCell, state)
1031+
1032+
eval(
1033+
"""
1034+
private val x = 341
1035+
f += x
1036+
protected val z = "abcd"
1037+
""".trimIndent(),
1038+
jupyterId = 2
1039+
)
1040+
assertTrue(state.isEmpty())
1041+
val setOfPrevCell = setOf("f")
1042+
assertNotEquals(setOfCell, setOfPrevCell)
1043+
1044+
eval(
1045+
"""
1046+
private val x = 341
1047+
protected val z = "abcd"
1048+
""".trimIndent(),
1049+
jupyterId = 2
1050+
)
1051+
assertTrue(state.isNotEmpty())
1052+
assertEquals(state, setOfPrevCell)
1053+
}
10141054
}

src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl/TrackedCellExecutor.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.jetbrains.kotlinx.jupyter.test.repl
22

33
import org.jetbrains.kotlinx.jupyter.ReplForJupyterImpl
4+
import org.jetbrains.kotlinx.jupyter.VariablesUsagesPerCellWatcher
45
import org.jetbrains.kotlinx.jupyter.api.Code
56
import org.jetbrains.kotlinx.jupyter.api.FieldValue
67
import org.jetbrains.kotlinx.jupyter.api.VariableState
@@ -48,6 +49,8 @@ internal class MockedInternalEvaluator : TrackedInternalEvaluator {
4849
override val variablesHolder = mutableMapOf<String, VariableState>()
4950
override val cellVariables = mutableMapOf<Int, MutableSet<String>>()
5051

52+
val variablesWatcher: VariablesUsagesPerCellWatcher<Int, String> = VariablesUsagesPerCellWatcher()
53+
5154
override val results: List<Any?>
5255
get() = executedCodes.map { null }
5356

@@ -64,6 +67,10 @@ internal class MockedInternalEvaluator : TrackedInternalEvaluator {
6467
}
6568
return -1
6669
}
70+
71+
override fun getUnchangedVariables(): Set<String> {
72+
return variablesWatcher.getUnchangedVariables()
73+
}
6774
}
6875

6976
internal class TrackedInternalEvaluatorImpl(private val baseEvaluator: InternalEvaluator) : TrackedInternalEvaluator, InternalEvaluator by baseEvaluator {

0 commit comments

Comments
 (0)