Permalink
Browse files

Add support for jvm-repr (#278)

  • Loading branch information...
alexarchambault committed Dec 12, 2018
1 parent 74e3568 commit c465f252666bb485b433f0bee646909faf4f8f7a
@@ -108,7 +108,10 @@ lazy val `scala-kernel-api` = project
crossVersion := CrossVersion.full,
generatePropertyFile("almond/almond.properties"),
generateDependenciesFile,
libraryDependencies += Deps.ammoniteRepl
libraryDependencies ++= Seq(
Deps.ammoniteRepl,
Deps.jvmRepr
)
)

lazy val `scala-interpreter` = project
@@ -43,6 +43,7 @@ Create a launcher with
```bash
$ SCALA_VERSION=2.12.7 ALMOND_VERSION=0.1.11-SNAPSHOT
$ coursier bootstrap \
-r jitpack \
-i user -I user:sh.almond:scala-kernel-api_$SCALA_VERSION:$ALMOND_VERSION \
sh.almond:scala-kernel_$SCALA_VERSION:$ALMOND_VERSION \
--sources --default=true \
@@ -12,6 +12,7 @@ For example, let's install almond for the scala `2.12.7` version,
```bash
$ SCALA_VERSION=2.12.7 ALMOND_VERSION=@VERSION@
$ coursier bootstrap @EXTRA_COURSIER_ARGS@\
-r jitpack \
-i user -I user:sh.almond:scala-kernel-api_$SCALA_VERSION:$ALMOND_VERSION \
sh.almond:scala-kernel_$SCALA_VERSION:$ALMOND_VERSION \
--sources --default=true \
@@ -26,6 +27,7 @@ Now let's *also* install almond for scala `2.11.12`,
```bash
$ SCALA_VERSION=2.11.12 ALMOND_VERSION=@VERSION@
$ coursier bootstrap @EXTRA_COURSIER_ARGS@\
-r jitpack \
-i user -I user:sh.almond:scala-kernel-api_$SCALA_VERSION:$ALMOND_VERSION \
sh.almond:scala-kernel_$SCALA_VERSION:$ALMOND_VERSION \
--sources --default=true \
@@ -11,6 +11,7 @@ so that nothing needs to be downloaded or picked from a cache upon launch. Passi
```bash
$ SCALA_VERSION=2.12.6 ALMOND_VERSION=0.1.7
$ coursier bootstrap --standalone \
-r jitpack \
-i user -I user:sh.almond:scala-kernel-api_$SCALA_VERSION:$ALMOND_VERSION \
sh.almond:scala-kernel_$SCALA_VERSION:$ALMOND_VERSION \
--sources --default=true \
@@ -6,6 +6,7 @@ Create a launcher via [coursier](http://get-coursier.io) with
```bash
$ SCALA_VERSION=@SCALA_VERSION@ ALMOND_VERSION=@VERSION@
$ coursier bootstrap @EXTRA_COURSIER_ARGS@\
-r jitpack \
-i user -I user:sh.almond:scala-kernel-api_$SCALA_VERSION:$ALMOND_VERSION \
sh.almond:scala-kernel_$SCALA_VERSION:$ALMOND_VERSION \
--sources --default=true \
@@ -22,11 +22,14 @@ import ammonite.runtime._
import ammonite.util._
import ammonite.util.Util.{newLine, normalizeNewlines}
import fastparse.Parsed
import jupyter.{Displayer, Displayers}
import metabrowse.server.{MetabrowseServer, Sourcepath}
import pprint.{TPrint, TPrintColors}

import scala.collection.mutable
import scala.concurrent.{Await, ExecutionContext}
import scala.concurrent.duration.Duration
import scala.reflect.ClassTag
import scala.tools.nsc.Global
import scala.util.{Failure, Random, Success}

@@ -233,7 +236,7 @@ final class ScalaInterpreter(
lazy val ammInterp: ammonite.interp.Interpreter = {

val replApi: ReplApiImpl =
new ReplApiImpl {
new ReplApiImpl { self =>
def replArgs0 = Vector.empty[Bind[_]]
def printer = printer0

@@ -267,6 +270,43 @@ final class ScalaInterpreter(
apply(normalizeNewlines(read(file)))
}
}

override protected[this] def internal0: FullReplAPI.Internal =
new FullReplAPI.Internal {
def pprinter = self.pprinter
def colors = self.colors
def replArgs: IndexedSeq[Bind[_]] = replArgs0

val defaultDisplayer = Displayers.registration().find(classOf[ScalaInterpreter.Foo])

override def print[T](
value: => T,
ident: String,
custom: Option[String]
)(implicit tprint: TPrint[T], tcolors: TPrintColors, classTagT: ClassTag[T]): Iterator[String] = {

val displayerPublishOpt =
if (classTagT == null)
None
else
currentPublishOpt.flatMap { p =>
Some(Displayers.registration().find(classTagT.runtimeClass))
.filter(_ ne defaultDisplayer)
.map(d => (d.asInstanceOf[Displayer[T]], p))
}

displayerPublishOpt match {
case None =>
super.print(value, ident, custom)(tprint, tcolors, classTagT)
case Some((displayer, publish)) =>
import scala.collection.JavaConverters._
val m = displayer.display(value)
val data = DisplayData(m.asScala.toMap)
publish.display(data)
Iterator()
}
}
}
}

val jupyterApi: JupyterApi =
@@ -814,4 +854,6 @@ object ScalaInterpreter {
}

}

private class Foo
}
@@ -170,6 +170,65 @@ object ScalaKernelTests extends TestSuite {
assert(replies == expectedReplies)
}

"jvm-repr" - {

// How the pseudo-client behaves

val sessionId = UUID.randomUUID().toString
val lastMsgId = UUID.randomUUID().toString

// When the pseudo-client exits

val stopWhen: (Channel, Message[Json]) => IO[Boolean] =
(_, m) =>
IO.pure(m.header.msg_type == "execute_reply" && m.parent_header.exists(_.msg_id == lastMsgId))

// Initial messages from client

val input = Stream(
execute(sessionId, """class Bar(val value: String)"""),
execute(sessionId, """kernel.register[Bar](bar => Map("text/plain" -> s"Bar(${bar.value})"))"""),
execute(sessionId, """val b = new Bar("other")""", lastMsgId)
)

val streams = ClientStreams.create(input, stopWhen)

val interpreter = new ScalaInterpreter(
initialColors = Colors.BlackWhite
)

val t = Kernel.create(interpreter, interpreterEc, threads)
.flatMap(_.run(streams.source, streams.sink))

t.unsafeRunTimedOrThrow(15.seconds)

val messageTypes = streams.generatedMessageTypes()

val expectedMessageTypes = Seq(
"execute_input",
"execute_result",
"execute_reply",
"execute_input",
"execute_reply",
"execute_input",
"display_data",
"execute_reply"
)

assert(messageTypes == expectedMessageTypes)

val displayData = streams.displayData

val expectedDisplayData = Seq(
Execute.DisplayData(
Map("text/plain" -> Json.jString("Bar(other)")),
Map()
) -> false
)

assert(displayData == expectedDisplayData)
}

"updatable display" - {

// How the pseudo-client behaves
@@ -1,6 +1,9 @@
package almond.api

import almond.interpreter.api.{CommHandler, OutputHandler}
import jupyter.{Displayer, Displayers}

import scala.reflect.{ClassTag, classTag}

trait JupyterApi { api =>

@@ -31,6 +34,15 @@ trait JupyterApi { api =>

final lazy val updatableResults: JupyterApi.UpdatableResults =
updatableResults0

def register[T: ClassTag](f: T => Map[String, String]): Unit =
Displayers.register(
classTag[T].runtimeClass.asInstanceOf[Class[T]],
new Displayer[T] {
import scala.collection.JavaConverters._
def display(t: T) = f(t).asJava
}
)
}

object JupyterApi {
@@ -6,7 +6,7 @@ import sbt.Keys.scalaVersion
object Deps {

object Versions {
def ammonite = "1.5.0"
def ammonite = "1.5.0-4-6296f20"
}

def ammoniteRepl = ("com.lihaoyi" % "ammonite-repl" % Versions.ammonite).cross(CrossVersion.full)
@@ -16,6 +16,7 @@ object Deps {
def caseApp = "com.github.alexarchambault" %% "case-app" % "2.0.0-M5"
def fs2 = "co.fs2" %% "fs2-core" % "0.10.5"
def jeromq = "org.zeromq" % "jeromq" % "0.4.3"
def jvmRepr = "com.github.jupyter" % "jvm-repr" % "0.3.1"
def metabrowseServer = ("org.scalameta" %% "metabrowse-server" % "0.2.0").exclude("org.slf4j", "slf4j-simple")
def scalaReflect = setting("org.scala-lang" % "scala-reflect" % scalaVersion.value)
def scalaRx = "com.lihaoyi" %% "scalarx" % "0.4.0"
@@ -22,7 +22,10 @@ object Settings {
"-language:higherKinds",
"-unchecked"
),
resolvers += Resolver.sonatypeRepo("releases"),
resolvers ++= Seq(
Resolver.sonatypeRepo("releases"),
"jitpack" at "https://jitpack.io"
),
// Seems required when cross-publishing for several scala versions
// with same major and minor numbers (e.g. 2.12.6 and 2.12.7)
publishConfiguration := publishConfiguration.value.withOverwrite(true),
@@ -39,6 +39,7 @@ fi
# sbt interpreter-api/publishLocal scala-kernel-api/publishLocal almond-spark/publishLocal
../scripts/coursier.sh launch \
-r sonatype:releases \
-r jitpack \
"com.geirsson:mdoc_$SCALA_VERSION:0.7.0" \
"sh.almond:scala-kernel-api_$SCALA_VERSION:$VERSION" \
-- \

0 comments on commit c465f25

Please sign in to comment.