You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zeppelin.apache.org by mo...@apache.org on 2016/11/14 19:00:25 UTC

[3/3] zeppelin git commit: Closes [ZEPPELIN-1505] Add Scio interpreter

Closes [ZEPPELIN-1505] Add Scio interpreter

### What is this PR for?

Closes #ZEPPELIN-1505. Adds Scio interpreter. Scio is a Scala DSL on top of Dataflow/Beam.
### What type of PR is it?

Improvement - ZEPPELIN-1505
### Todos
- [x] - test integration with zeppelin context (zeppelin context is too tightly coupled withs spark)
- [x] - what to do about code completion?
- [x] - add more tests?
- [x] - add helpers to display data
- [x] - add doc in `docs/interpreter/scio`
### What is the Jira issue?

https://issues.apache.org/jira/browse/ZEPPELIN-1505
### How should this be tested?

```
mvn -pl scio,zeppelin-display,zeppelin-interpreter -Dtest='org.apache.zeppelin.scio.*' -DfailIfNoTests=false test
```
### Screenshots

![GitHub Logo](http://i.imgur.com/w6Cp5kp.png)
### Questions:
- Does the licenses files need update? ~~no~~ yes
- Is there breaking changes for older versions? no
- Does this needs documentation? yes (included in the PR)

Author: Rafal Wojdyla <ra...@spotify.com>

Closes #1471 from ravwojdyla/scio and squashes the following commits:

d6fbc4e [Rafal Wojdyla] Add runner doc links
7e6fdec [Rafal Wojdyla] Fix indentation
d8de7c8 [Rafal Wojdyla] Remove optional flink deps from Beam
508705f [Rafal Wojdyla] Remove duplicates
49cf0eb [Rafal Wojdyla] Add scio to beam group
cd79fc8 [Rafal Wojdyla] Add .bigquery cache to gitignore
b961791 [Rafal Wojdyla] Check the message content
1e30f76 [Rafal Wojdyla] Simplify SCollection implicits
3c519f1 [Rafal Wojdyla] Fix doc style
e9579d8 [Rafal Wojdyla] Clarify Context sharing + add docs about display helpers
327273e [Rafal Wojdyla] Add Zeppelin custom ContextAndArgs
0920fdd [Rafal Wojdyla] Remove obsolete deps
8f25f71 [Rafal Wojdyla] Upgrade scio to 0.2.4
3275185 [Rafal Wojdyla] Add license
bd4df5e [Rafal Wojdyla] Fix documentation style
dcbb197 [Rafal Wojdyla] Add documentation link
e635674 [Rafal Wojdyla] Add tests for DisplayHelpers
c0f8ccf [Rafal Wojdyla] Fix style and number of records for take
9dcc8ce [Rafal Wojdyla] Add display helpers for Tap[T] and Future[Tap[T]]
4014c81 [Rafal Wojdyla] Parse params generic params
0305a3c [Rafal Wojdyla] Style fix
a92494b [Rafal Wojdyla] Style + use `split` to support both scala 2.{10,11}
b884b72 [Rafal Wojdyla] Fix tests - add exception and check messages
99a7daa [Rafal Wojdyla] Progress should be 0
7b54e49 [Rafal Wojdyla] No need to override delegation for completion
12f0096 [Rafal Wojdyla] Clean up tests
93233a8 [Rafal Wojdyla] Rename argz param, fix style
0a3b49a [Rafal Wojdyla] Add Scio doc
61850d7 [Rafal Wojdyla] Add TableRow display helper + style
be252f8 [Rafal Wojdyla] Add avro display
89a2811 [Rafal Wojdyla] Add limit of display
9a21aa0 [Rafal Wojdyla] Add display helpers
6ff4e95 [Rafal Wojdyla] Inject argz to the Scio interpreter
570cfaa [Rafal Wojdyla] Add Scio interpreter tests
38abaf9 [Rafal Wojdyla] Add Scio interpreter
7b596ea [Rafal Wojdyla] Generalize SparkOutputStream


Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo
Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/f127237f
Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/f127237f
Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/f127237f

Branch: refs/heads/master
Commit: f127237fb1f774d540ce9d8e5885c0dddd35419a
Parents: c9adf71
Author: Rafal Wojdyla <ra...@spotify.com>
Authored: Sat Nov 5 23:36:57 2016 +0100
Committer: Lee moon soo <mo...@apache.org>
Committed: Mon Nov 14 11:00:15 2016 -0800

----------------------------------------------------------------------
 .gitignore                                      |   3 +
 beam/pom.xml                                    |  36 +-
 .../src/main/resources/interpreter-setting.json |  22 +
 conf/interpreter-list                           |   1 +
 conf/zeppelin-site.xml.template                 |   2 +-
 docs/_includes/themes/zeppelin/_navigation.html |   1 +
 docs/interpreter/scio.md                        | 168 ++++++
 flink/pom.xml                                   |   7 -
 pom.xml                                         |  10 +-
 scio/README.md                                  |  18 +
 scio/pom.xml                                    | 240 ++++++++
 .../apache/zeppelin/scio/ContextAndArgs.scala   |  41 ++
 .../apache/zeppelin/scio/DisplayHelpers.scala   | 160 ++++++
 .../scio/DisplaySCollectionImplicits.scala      | 105 ++++
 .../zeppelin/scio/DisplayTapImplicits.scala     | 154 ++++++
 .../apache/zeppelin/scio/ScioInterpreter.scala  | 201 +++++++
 scio/src/test/avro/schema.avsc                  |  12 +
 .../zeppelin/scio/ScioInterpreterTest.java      | 118 ++++
 scio/src/test/resources/log4j.properties        |  22 +
 .../scio/DisplayHelpersTestScala211.scala       |  55 ++
 .../apache/zeppelin/scio/TestCCScala211.scala   |  22 +
 .../zeppelin/scio/DisplayHelpersTest.scala      | 548 +++++++++++++++++++
 .../scala/org/apache/zeppelin/scio/TestCC.scala |  24 +
 .../apache/zeppelin/scio/util/TestUtils.scala   |  50 ++
 spark/pom.xml                                   |  28 +-
 .../apache/zeppelin/spark/LogOutputStream.java  | 116 ----
 .../zeppelin/spark/PySparkInterpreter.java      |   5 +-
 .../apache/zeppelin/spark/SparkInterpreter.java |   5 +-
 .../zeppelin/spark/SparkOutputStream.java       |  88 ---
 .../org/apache/zeppelin/spark/ZeppelinR.java    |   5 +-
 zeppelin-distribution/src/bin_license/LICENSE   | 111 +++-
 .../bin_license/licenses/LICENSE-java-lsh-0.10  |   7 +
 .../LICENSE-java-string-similarity-0.12         |   7 +
 .../bin_license/licenses/LICENSE-jsoup-1.6.1    |  21 +
 .../licenses/LICENSE-jtransforms-2.4.0          |  33 ++
 .../licenses/LICENSE-junit-interface-0.11       |  24 +
 .../licenses/LICENSE-kryo-shaded-3.0.3          |  10 +
 .../bin_license/licenses/LICENSE-minilog-1.3.0  |  10 +
 .../licenses/LICENSE-sbt-test-interface-1.0     |  25 +
 .../licenses/LICENSE-scalamacros-paradise-2.1.0 |  27 +
 .../LICENSE-scalamacros-quasiquotes-2.1.0       |  27 +
 .../licenses/LICENSE-slf4j-simple-1.7.21        |  21 +
 .../bin_license/licenses/LICENSE-spire-0.7.4    |  19 +
 .../licenses/LICENSE-spire-macros-0.7.4         |  19 +
 .../util/InterpreterOutputStream.java           |  91 +++
 .../interpreter/util/LogOutputStream.java       | 115 ++++
 zeppelin-zengine/pom.xml                        |   6 -
 .../zeppelin/conf/ZeppelinConfiguration.java    |   5 +-
 48 files changed, 2549 insertions(+), 296 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 6352f7b..1d37d39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,6 +52,9 @@ zeppelin-web/bower_components
 .Rhistory
 /R/
 
+# scio
+.bigquery/
+
 # project level
 /logs/
 /run/

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/beam/pom.xml
----------------------------------------------------------------------
diff --git a/beam/pom.xml b/beam/pom.xml
index b0f1656..dc31594 100644
--- a/beam/pom.xml
+++ b/beam/pom.xml
@@ -102,7 +102,13 @@
         </exclusion>
       </exclusions>
     </dependency>
-  
+
+    <dependency>
+      <groupId>org.apache.zeppelin</groupId>
+      <artifactId>zeppelin-scio_${scala.binary.version}</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
     <dependency>
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-hdfs</artifactId>
@@ -175,34 +181,6 @@
       <artifactId>beam-runners-direct-java</artifactId>
       <version>${beam.beam.version}</version>
     </dependency>
-  
-    <dependency>
-      <groupId>org.apache.beam</groupId>
-      <artifactId>beam-runners-flink_2.10</artifactId>
-      <version>${beam.beam.version}</version>
-      <exclusions>
-        <exclusion>
-          <artifactId>slf4j-log4j12</artifactId>
-          <groupId>org.slf4j</groupId>
-        </exclusion>
-        <exclusion>
-          <artifactId>netty-all</artifactId>
-          <groupId>io.netty</groupId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-  
-    <dependency>
-      <groupId>org.apache.beam</groupId>
-      <artifactId>beam-runners-flink_2.10-examples</artifactId>
-      <version>${beam.beam.version}</version>
-      <exclusions>
-        <exclusion>
-          <artifactId>slf4j-log4j12</artifactId>
-          <groupId>org.slf4j</groupId>
-        </exclusion>
-      </exclusions>
-    </dependency>
     
     <dependency>
       <groupId>javax.servlet</groupId>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/beam/src/main/resources/interpreter-setting.json
----------------------------------------------------------------------
diff --git a/beam/src/main/resources/interpreter-setting.json b/beam/src/main/resources/interpreter-setting.json
index 189e08b..428b76d 100644
--- a/beam/src/main/resources/interpreter-setting.json
+++ b/beam/src/main/resources/interpreter-setting.json
@@ -9,5 +9,27 @@
     "editor": {
       "editOnDblClick": false
     }
+  },
+  {
+    "group": "beam",
+    "name": "scio",
+    "className": "org.apache.zeppelin.scio.ScioInterpreter",
+    "properties": {
+      "zeppelin.scio.argz": {
+        "envName": "ZEPPELIN_SCIO_ARGZ",
+        "propertyName": "zeppelin.scio.argz",
+        "defaultValue": "--runner=InProcessPipelineRunner",
+        "description": "Scio interpreter wide arguments"
+      },
+      "zeppelin.scio.maxResult": {
+        "envName": "ZEPPELIN_SCIO_MAXRESULT",
+        "propertyName": "zeppelin.scio.maxResult",
+        "defaultValue": "1000",
+        "description": "Max number of SCollection results to display."
+      }
+    },
+    "editor": {
+      "language": "scala"
+    }
   }
 ]

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/conf/interpreter-list
----------------------------------------------------------------------
diff --git a/conf/interpreter-list b/conf/interpreter-list
index 38cb386..c22afef 100644
--- a/conf/interpreter-list
+++ b/conf/interpreter-list
@@ -35,4 +35,5 @@ md              org.apache.zeppelin:zeppelin-markdown:0.6.1             Markdown
 pig             org.apache.zeppelin:zeppelin-pig:0.6.1                  Pig interpreter
 postgresql      org.apache.zeppelin:zeppelin-postgresql:0.6.1           Postgresql interpreter
 python          org.apache.zeppelin:zeppelin-python:0.6.1               Python interpreter
+scio            org.apache.zeppelin:zeppelin-scio:0.6.1                 Scio interpreter
 shell           org.apache.zeppelin:zeppelin-shell:0.6.1                Shell command

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/conf/zeppelin-site.xml.template
----------------------------------------------------------------------
diff --git a/conf/zeppelin-site.xml.template b/conf/zeppelin-site.xml.template
index c4b369c..36f7e19 100755
--- a/conf/zeppelin-site.xml.template
+++ b/conf/zeppelin-site.xml.template
@@ -190,7 +190,7 @@
 
 <property>
   <name>zeppelin.interpreters</name>
-  <value>org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.rinterpreter.RRepl,org.apache.zeppelin.rinterpreter.KnitR,org.apache.zeppelin.spark.SparkRInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.file.HDFSFileInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,,org.apache.zeppelin.python.PythonInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.postgresql.PostgreSqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,or
 g.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.alluxio.AlluxioInterpreter,org.apache.zeppelin.hbase.HbaseInterpreter,org.apache.zeppelin.livy.LivySparkInterpreter,org.apache.zeppelin.livy.LivyPySparkInterpreter,org.apache.zeppelin.livy.LivySparkRInterpreter,org.apache.zeppelin.livy.LivySparkSQLInterpreter,org.apache.zeppelin.bigquery.BigQueryInterpreter,org.apache.zeppelin.beam.BeamInterpreter,org.apache.zeppelin.pig.PigInterpreter, org.apache.zeppelin.pig.PigQueryInterpreter</value>
+  <value>org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.rinterpreter.RRepl,org.apache.zeppelin.rinterpreter.KnitR,org.apache.zeppelin.spark.SparkRInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.file.HDFSFileInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,,org.apache.zeppelin.python.PythonInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.postgresql.PostgreSqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,or
 g.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.alluxio.AlluxioInterpreter,org.apache.zeppelin.hbase.HbaseInterpreter,org.apache.zeppelin.livy.LivySparkInterpreter,org.apache.zeppelin.livy.LivyPySparkInterpreter,org.apache.zeppelin.livy.LivySparkRInterpreter,org.apache.zeppelin.livy.LivySparkSQLInterpreter,org.apache.zeppelin.bigquery.BigQueryInterpreter,org.apache.zeppelin.beam.BeamInterpreter,org.apache.zeppelin.pig.PigInterpreter,org.apache.zeppelin.pig.PigQueryInterpreter,org.apache.zeppelin.scio.ScioInterpreter</value>
   <description>Comma separated interpreter configurations. First interpreter become a default</description>
 </property>
 

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/docs/_includes/themes/zeppelin/_navigation.html
----------------------------------------------------------------------
diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html
index ba98347..e15fa9f 100644
--- a/docs/_includes/themes/zeppelin/_navigation.html
+++ b/docs/_includes/themes/zeppelin/_navigation.html
@@ -69,6 +69,7 @@
                 <li><a href="{{BASE_PATH}}/interpreter/postgresql.html">Postgresql, HAWQ</a></li>
                 <li><a href="{{BASE_PATH}}/interpreter/r.html">R</a></li>
                 <li><a href="{{BASE_PATH}}/interpreter/scalding.html">Scalding</a></li>
+                <li><a href="{{BASE_PATH}}/interpreter/scio.html">Scio</a></li>
                 <li><a href="{{BASE_PATH}}/interpreter/shell.html">Shell</a></li>
                 <li><a href="{{BASE_PATH}}/interpreter/spark.html">Spark</a></li>
               </ul>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/docs/interpreter/scio.md
----------------------------------------------------------------------
diff --git a/docs/interpreter/scio.md b/docs/interpreter/scio.md
new file mode 100644
index 0000000..83a48d0
--- /dev/null
+++ b/docs/interpreter/scio.md
@@ -0,0 +1,168 @@
+---
+layout: page
+title: "Scio Interpreter for Apache Zeppelin"
+description: "Scio is a Scala DSL for Apache Beam/Google Dataflow model."
+group: interpreter
+---
+<!--
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+{% include JB/setup %}
+
+# Scio Interpreter for Apache Zeppelin
+
+<div id="toc"></div>
+
+## Overview
+Scio is a Scala DSL for [Google Cloud Dataflow](https://github.com/GoogleCloudPlatform/DataflowJavaSDK) and [Apache Beam](http://beam.incubator.apache.org/) inspired by [Spark](http://spark.apache.org/) and [Scalding](https://github.com/twitter/scalding). See the current [wiki](https://github.com/spotify/scio/wiki) and [API documentation](http://spotify.github.io/scio/) for more information.
+
+## Configuration
+<table class="table-configuration">
+  <tr>
+    <th>Name</th>
+    <th>Default Value</th>
+    <th>Description</th>
+  </tr>
+  <tr>
+    <td>zeppelin.scio.argz</td>
+    <td>--runner=InProcessPipelineRunner</td>
+    <td>Scio interpreter wide arguments. Documentation: https://github.com/spotify/scio/wiki#options and https://cloud.google.com/dataflow/pipelines/specifying-exec-params</td>
+  </tr>
+  <tr>
+    <td>zeppelin.scio.maxResult</td>
+    <td>1000</td>
+    <td>Max number of SCollection results to display</td>
+  </tr>
+
+</table>
+
+## Enabling the Scio Interpreter
+
+In a notebook, to enable the **Scio** interpreter, click the **Gear** icon and select **beam** (**beam.scio**).
+
+## Using the Scio Interpreter
+
+In a paragraph, use `$beam.scio` to select the **Scio** interpreter. You can use it much the same way as vanilla Scala REPL and [Scio REPL](https://github.com/spotify/scio/wiki/Scio-REPL). State (like variables, imports, execution etc) is shared among all *Scio* paragraphs. There is a special variable **argz** which holds arguments from Scio interpreter settings. The easiest way to proceed is to create a Scio context via standard `ContextAndArgs`.
+
+```scala
+$beam.scio
+val (sc, args) = ContextAndArgs(argz)
+```
+
+Use `sc` context the way you would in regular pipeline/REPL.
+
+Example:
+
+```scala
+$beam.scio
+val (sc, args) = ContextAndArgs(argz)
+sc.parallelize(Seq("foo", "foo", "bar")).countByValue.closeAndDisplay()
+```
+
+If you close Scio context, go ahead an create a new one using `ContextAndArgs`. Please refer to [Scio wiki](https://github.com/spotify/scio/wiki) for more complex examples. You can close Scio context much the same way as in Scio REPL, and use Zeppelin display helpers to synchronously close and display results - read more below.
+
+### Progress
+
+There can be only one paragraph running at a time. There is no notion of overall progress, thus progress bar will be `0`.
+
+### SCollection display helpers
+
+Scio interpreter comes with display helpers to ease working with Zeppelin notebooks. Simply use `closeAndDisplay()` on `SCollection` to close context and display the results. The number of results is limited by `zeppelin.scio.maxResult` (by default 1000).
+
+Supported `SCollection` types:
+
+ * Scio's typed BigQuery
+ * Scala's Products (case classes, tuples)
+ * Google BigQuery's TableRow
+ * Apache Avro
+ * All Scala's `AnyVal`
+
+#### Helper methods
+
+There are different helper methods for different objects. You can easily display results from `SCollection`, `Future[Tap]` and `Tap`.
+
+##### `SCollection` helper
+
+`SCollection` has `closeAndDisplay` Zeppelin helper method for types listed above. Use it to synchronously close Scio context, once available pull and display results.
+
+##### `Future[Tap]` helper
+
+`Future[Tap]` has `waitAndDisplay` Zeppelin helper method for types listed above. Use it synchronously wait for results, once available pull and display results.
+
+##### `Tap` helper
+
+`Tap` has `display` Zeppelin helper method for types listed above. Use it to pull and display results.
+
+### Examples
+
+#### BigQuery example:
+
+```scala
+$beam.scio
+@BigQueryType.fromQuery("""|SELECT departure_airport,count(case when departure_delay>0 then 1 else 0 end) as no_of_delays
+                           |FROM [bigquery-samples:airline_ontime_data.flights]
+                           |group by departure_airport
+                           |order by 2 desc
+                           |limit 10""".stripMargin) class Flights
+
+val (sc, args) = ContextAndArgs(argz)
+sc.bigQuerySelect(Flights.query).closeAndDisplay(Flights.schema)
+```
+
+#### BigQuery typed example:
+
+```scala
+$beam.scio
+@BigQueryType.fromQuery("""|SELECT departure_airport,count(case when departure_delay>0 then 1 else 0 end) as no_of_delays
+                           |FROM [bigquery-samples:airline_ontime_data.flights]
+                           |group by departure_airport
+                           |order by 2 desc
+                           |limit 10""".stripMargin) class Flights
+
+val (sc, args) = ContextAndArgs(argz)
+sc.typedBigQuery[Flights]().flatMap(_.no_of_delays).mean.closeAndDisplay()
+```
+
+#### Avro example:
+
+```scala
+$beam.scio
+import com.spotify.data.ExampleAvro
+
+val (sc, args) = ContextAndArgs(argz)
+sc.avroFile[ExampleAvro]("gs://<bucket>/tmp/my.avro").take(10).closeAndDisplay()
+```
+
+#### Avro example with a view schema:
+
+```scala
+$beam.scio
+import com.spotify.data.ExampleAvro
+import org.apache.avro.Schema
+
+val (sc, args) = ContextAndArgs(argz)
+val view = Schema.parse("""{"type":"record","name":"ExampleAvro","namespace":"com.spotify.data","fields":[{"name":"track","type":"string"}, {"name":"artist", "type":"string"}]}""")
+
+sc.avroFile[EndSongCleaned]("gs://<bucket>/tmp/my.avro").take(10).closeAndDisplay(view)
+```
+
+### Google credentials
+
+Scio Interpreter will try to infer your Google Cloud credentials from its environment, it will take into the account:
+ * `argz` interpreter settings ([doc](https://github.com/spotify/scio/wiki#options))
+ * environment variable (`GOOGLE_APPLICATION_CREDENTIALS`)
+ * gcloud configuration
+
+#### BigQuery macro credentials
+
+Currently BigQuery project for macro expansion is inferred using Google Dataflow's [DefaultProjectFactory().create()](https://github.com/GoogleCloudPlatform/DataflowJavaSDK/blob/master/sdk/src/main/java/com/google/cloud/dataflow/sdk/options/GcpOptions.java#L187)

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/flink/pom.xml
----------------------------------------------------------------------
diff --git a/flink/pom.xml b/flink/pom.xml
index 5ba7e33..1885a1f 100644
--- a/flink/pom.xml
+++ b/flink/pom.xml
@@ -313,13 +313,6 @@
               <includeScope>runtime</includeScope>
             </configuration>
           </execution>
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <executions>
           <execution>
             <id>copy-artifact</id>
             <phase>package</phase>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c9b4e02..80b0373 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,7 @@
     <module>elasticsearch</module>
     <module>bigquery</module>
     <module>alluxio</module>
+    <module>scio</module>
     <module>zeppelin-web</module>
     <module>zeppelin-server</module>
     <module>zeppelin-distribution</module>
@@ -589,7 +590,14 @@
         <module>beam</module>
       </modules>
     </profile>
-    
+
+    <profile>
+      <id>scio</id>
+      <modules>
+        <module>scio</module>
+      </modules>
+    </profile>
+
     <profile>
       <id>examples</id>
       <modules>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/README.md
----------------------------------------------------------------------
diff --git a/scio/README.md b/scio/README.md
new file mode 100644
index 0000000..b95c548
--- /dev/null
+++ b/scio/README.md
@@ -0,0 +1,18 @@
+Scio interpreter for Apache Zeppelin
+====================================
+
+## Raison d'�tre:
+
+Provide Scio Interpreter for Zeppelin.
+
+## Build
+
+```
+mvn -pl zeppelin-interpreter,zeppelin-display,scio -DskipTests package
+```
+
+## Test
+
+```
+mvn -pl scio,zeppelin-display,zeppelin-interpreter -Dtest='org.apache.zeppelin.scio.*' -DfailIfNoTests=false test
+```

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/pom.xml
----------------------------------------------------------------------
diff --git a/scio/pom.xml b/scio/pom.xml
new file mode 100644
index 0000000..27f5433
--- /dev/null
+++ b/scio/pom.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <artifactId>zeppelin</artifactId>
+    <groupId>org.apache.zeppelin</groupId>
+    <version>0.7.0-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+
+  <groupId>org.apache.zeppelin</groupId>
+  <artifactId>zeppelin-scio_2.10</artifactId>
+  <packaging>jar</packaging>
+  <version>0.7.0-SNAPSHOT</version>
+  <name>Zeppelin: Scio</name>
+  <description>Zeppelin Scio support</description>
+
+  <properties>
+    <scio.version>0.2.4</scio.version>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>zeppelin-interpreter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.spotify</groupId>
+      <artifactId>scio-repl_${scala.binary.version}</artifactId>
+      <version>${scio.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>14.0.1</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-library</artifactId>
+      <version>${scala.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-compiler</artifactId>
+      <version>${scala.version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.scala-lang</groupId>
+      <artifactId>scala-reflect</artifactId>
+      <version>${scala.version}</version>
+    </dependency>
+
+    <!--TEST-->
+    <dependency>
+      <groupId>org.scalatest</groupId>
+      <artifactId>scalatest_${scala.binary.version}</artifactId>
+      <version>${scalatest.version}</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-enforcer-plugin</artifactId>
+        <version>1.3.1</version>
+        <executions>
+          <execution>
+            <id>enforce</id>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.17</version>
+        <configuration>
+          <forkCount>1</forkCount>
+          <reuseForks>false</reuseForks>
+          <argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>2.3</version>
+        <configuration>
+          <filters>
+            <filter>
+              <artifact>*:*</artifact>
+              <excludes>
+                <exclude>META-INF/*.SF</exclude>
+                <exclude>META-INF/*.DSA</exclude>
+                <exclude>META-INF/*.RSA</exclude>
+              </excludes>
+            </filter>
+          </filters>
+          <transformers>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+              <resource>reference.conf</resource>
+            </transformer>
+          </transformers>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.8</version>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/../../interpreter/scio</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>false</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+              <includeScope>runtime</includeScope>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>${project.groupId}</groupId>
+                  <artifactId>${project.artifactId}</artifactId>
+                  <version>${project.version}</version>
+                  <type>${project.packaging}</type>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Plugin to compile Scala code -->
+      <plugin>
+        <groupId>org.scala-tools</groupId>
+        <artifactId>maven-scala-plugin</artifactId>
+        <version>2.15.2</version>
+        <executions>
+          <execution>
+            <id>compile</id>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+            <phase>compile</phase>
+          </execution>
+          <execution>
+            <id>test-compile</id>
+            <goals>
+              <goal>testCompile</goal>
+            </goals>
+            <phase>test-compile</phase>
+          </execution>
+          <execution>
+            <phase>process-resources</phase>
+            <goals>
+              <goal>compile</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+
+      <!-- Plugin to compile avro for tests -->
+      <plugin>
+        <groupId>org.apache.avro</groupId>
+        <artifactId>avro-maven-plugin</artifactId>
+        <version>1.7.7</version>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>schema</goal>
+            </goals>
+            <configuration>
+              <sourceDirectory>${project.basedir}/src/test/avro/</sourceDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/main/scala/org/apache/zeppelin/scio/ContextAndArgs.scala
----------------------------------------------------------------------
diff --git a/scio/src/main/scala/org/apache/zeppelin/scio/ContextAndArgs.scala b/scio/src/main/scala/org/apache/zeppelin/scio/ContextAndArgs.scala
new file mode 100644
index 0000000..cb1b390
--- /dev/null
+++ b/scio/src/main/scala/org/apache/zeppelin/scio/ContextAndArgs.scala
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+import com.google.cloud.dataflow.sdk.options.PipelineOptions
+import com.spotify.scio.repl.ReplScioContext
+import com.spotify.scio.{Args, ScioContext}
+
+/**
+ * Convenience object for creating [[com.spotify.scio.ScioContext]] and [[com.spotify.scio.Args]].
+ */
+object ContextAndArgs {
+  def apply(argz: Array[String]): (ScioContext, Args) = {
+    val (dfOpts, args) = ScioContext.parseArguments[PipelineOptions](argz)
+
+    val nextReplJar = this
+      .getClass
+      .getClassLoader
+      .asInstanceOf[{def getNextReplCodeJarPath: String}].getNextReplCodeJarPath
+
+    val sc = new ReplScioContext(dfOpts, List(nextReplJar))
+    sc.setName("sciozeppelin")
+
+    (sc, args)
+  }
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/main/scala/org/apache/zeppelin/scio/DisplayHelpers.scala
----------------------------------------------------------------------
diff --git a/scio/src/main/scala/org/apache/zeppelin/scio/DisplayHelpers.scala b/scio/src/main/scala/org/apache/zeppelin/scio/DisplayHelpers.scala
new file mode 100644
index 0000000..cdf718c
--- /dev/null
+++ b/scio/src/main/scala/org/apache/zeppelin/scio/DisplayHelpers.scala
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+import com.google.api.services.bigquery.model.TableSchema
+import com.spotify.scio.bigquery._
+import org.apache.avro.Schema
+import org.apache.avro.generic.GenericRecord
+
+import scala.reflect.ClassTag
+
+/**
+ * Set of helpers for Zeppelin Display system.
+ */
+private[scio] object DisplayHelpers {
+
+  private[scio] val sCollectionEmptyMsg =
+    "\n%html <font color=red>Result SCollection is empty!</font>\n"
+  private val maxResults = Integer.getInteger("zeppelin.scio.maxResult", 1000)
+  private[scio] val tab = "\t"
+  private[scio] val newline = "\n"
+  private[scio] val table = "%table"
+  private[scio] val rowLimitReachedMsg =
+    s"$newline<font color=red>Results are limited to " + maxResults + s" rows.</font>$newline"
+  private[scio] val bQSchemaIncomplete =
+    s"$newline<font color=red>Provided BigQuery Schema has not fields!</font>$newline"
+
+  private def notifyIfTruncated(it: Iterator[_]): Unit = {
+    if(it.hasNext) println(rowLimitReachedMsg)
+  }
+
+  /**
+   * Displays [[AnyVal]] values from given [[Iterator]].
+   */
+  private[scio] def displayAnyVal[T: ClassTag](it: Iterator[T], printer: (T) => String): Unit = {
+    if (it.isEmpty) {
+      println(sCollectionEmptyMsg)
+    } else {
+      println(s"$table value$newline${it.take(maxResults).map(printer).mkString(newline)}")
+      notifyIfTruncated(it)
+    }
+  }
+
+  /**
+   * Displays [[String]] values from given [[Iterator]].
+   */
+  private[scio] def displayString[T: ClassTag](it: Iterator[T], printer: (T) => String): Unit = {
+    if (it.isEmpty) {
+      println(sCollectionEmptyMsg)
+    } else {
+      println(s"$table value$newline${it.take(maxResults).map(printer).mkString(newline)}")
+      notifyIfTruncated(it)
+    }
+  }
+
+  /**
+   * Displays [[com.google.cloud.dataflow.sdk.values.KV]] values from given [[Iterator]].
+   */
+  private[scio] def displayKV[K: ClassTag, V: ClassTag](it: Iterator[(K,V)]): Unit = {
+    if (it.isEmpty) {
+      println(sCollectionEmptyMsg)
+    } else {
+      val content = it.take(maxResults).map{ case (k, v) => s"$k$tab$v" }.mkString(newline)
+      println(s"$table key${tab}value$newline$content")
+      notifyIfTruncated(it)
+    }
+  }
+
+  /**
+   * Displays [[Product]] values from given [[Iterator]].
+   */
+  private[scio] def displayProduct[T: ClassTag](it: Iterator[T])
+                                               (implicit ev: T <:< Product): Unit = {
+    if (it.isEmpty) {
+      println(sCollectionEmptyMsg)
+    } else {
+      val first = it.next()
+      //TODO is this safe field name to value iterator?
+      val fieldNames = first.getClass.getDeclaredFields.map(_.getName)
+
+      val header = fieldNames.mkString(tab)
+      val firstStr = first.productIterator.mkString(tab)
+      val content = it.take(maxResults - 1).map(_.productIterator.mkString(tab)).mkString(newline)
+      println(s"$table $header$newline$firstStr$newline$content")
+      notifyIfTruncated(it)
+    }
+  }
+
+  /**
+   * Displays Avro values from given [[Iterator]] using optional [[Schema]].
+   * @param schema optional "view" schema, otherwise schema is inferred from the first object
+   */
+  private[scio] def displayAvro[T: ClassTag](it: Iterator[T], schema: Schema = null)
+                                            (implicit ev: T <:< GenericRecord): Unit = {
+    if (it.isEmpty) {
+      println(sCollectionEmptyMsg)
+    } else {
+      val first = it.next()
+      import collection.JavaConverters._
+
+      val fieldNames = if (schema != null) {
+        schema.getFields.iterator().asScala.map(_.name()).toArray
+      } else {
+        first.getSchema.getFields.iterator.asScala.map(_.name()).toArray
+      }
+
+      val header = fieldNames.mkString(tab)
+      val firstStr = fieldNames.map(first.get).mkString(tab)
+      val content = it.take(maxResults - 1)
+        .map(r => fieldNames.map(r.get).mkString(tab))
+        .mkString(newline)
+      println(s"$table $header$newline$firstStr$newline$content")
+      notifyIfTruncated(it)
+    }
+  }
+
+  /**
+   * Displays [[TableRow]] values from given [[Iterator]] using specified [[TableSchema]].
+   */
+  private[scio] def displayBQTableRow[T: ClassTag](it: Iterator[T], schema: TableSchema)
+                                                  (implicit ev: T <:< TableRow) : Unit = {
+    if (it.isEmpty) {
+      println(sCollectionEmptyMsg)
+    } else {
+      import collection.JavaConverters._
+      val fieldsOp = Option(schema.getFields)
+      fieldsOp match {
+        case None => println(bQSchemaIncomplete)
+        case Some(f) => {
+          val fields = f.asScala.map(_.getName).toArray
+
+          val header = fields.mkString(tab)
+
+          val content = it.take(maxResults)
+            .map(r => fields.map(r.get).mkString(tab))
+            .mkString(newline)
+
+          println(s"$table $header$newline$content")
+          notifyIfTruncated(it)
+        }
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/main/scala/org/apache/zeppelin/scio/DisplaySCollectionImplicits.scala
----------------------------------------------------------------------
diff --git a/scio/src/main/scala/org/apache/zeppelin/scio/DisplaySCollectionImplicits.scala b/scio/src/main/scala/org/apache/zeppelin/scio/DisplaySCollectionImplicits.scala
new file mode 100644
index 0000000..566e106
--- /dev/null
+++ b/scio/src/main/scala/org/apache/zeppelin/scio/DisplaySCollectionImplicits.scala
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+import com.google.api.services.bigquery.model.TableSchema
+import com.spotify.scio._
+import com.spotify.scio.bigquery._
+import com.spotify.scio.values.SCollection
+import org.apache.avro.Schema
+import org.apache.avro.generic.GenericRecord
+
+import scala.reflect.ClassTag
+
+/**
+ * Implicit Zeppelin display helpers for SCollection.
+ */
+object DisplaySCollectionImplicits {
+
+  private def materialize[T: ClassTag](self: SCollection[T]) = {
+    val f = self.materialize
+    self.context.close()
+    f
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinSCollection[T: ClassTag](private val self: SCollection[T])(implicit ev: T <:< AnyVal) extends AnyVal {
+  implicit class ZeppelinSCollection[T: ClassTag](val self: SCollection[T])
+                                                 (implicit ev: T <:< AnyVal) {
+    /** Convenience method to close the current [[com.spotify.scio.ScioContext]]
+     * and display elements from SCollection. */
+    def closeAndDisplay(printer: (T) => String = (e: T) => e.toString): Unit = {
+      DisplayTapImplicits.ZeppelinTap(materialize(self).waitForResult()).display(printer)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinSCollection[T: ClassTag](private val self: SCollection[T]) extends AnyVal {
+  implicit class ZeppelinStringSCollection[T: ClassTag](val self: SCollection[T])
+                                                       (implicit ev: T <:< String) {
+    /** Convenience method to close the current [[com.spotify.scio.ScioContext]]
+     * and display elements from SCollection. */
+    def closeAndDisplay(printer: (T) => String = (e: T) => e.toString): Unit = {
+      DisplayTapImplicits.ZeppelinStringTap(materialize(self).waitForResult()).display(printer)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinKVSCollection[K: ClassTag, V: ClassTag](val self: SCollection[(K, V)]) extends AnyVal {
+  implicit class ZeppelinKVSCollection[K: ClassTag, V: ClassTag](val self: SCollection[(K, V)]) {
+    /** Convenience method to close the current [[com.spotify.scio.ScioContext]]
+     * and display elements from KV SCollection. */
+    def closeAndDisplay(): Unit = {
+      DisplayTapImplicits.ZeppelinKVTap(materialize(self).waitForResult()).display()
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinProductSCollection[T: ClassTag](val self: SCollection[T])(implicit ev: T <:< Product) extends AnyVal {
+  implicit class ZeppelinProductSCollection[T: ClassTag](val self: SCollection[T])
+                                                        (implicit ev: T <:< Product) {
+    /** Convenience method to close the current [[com.spotify.scio.ScioContext]]
+     * and display elements from Product like SCollection */
+    def closeAndDisplay(): Unit = {
+      DisplayTapImplicits.ZeppelinProductTap(materialize(self).waitForResult()).display()
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinAvroSCollection[T: ClassTag](val self: SCollection[T])(implicit ev: T <:< GenericRecord) extends AnyVal {
+  implicit class ZeppelinAvroSCollection[T: ClassTag](val self: SCollection[T])
+                                                     (implicit ev: T <:< GenericRecord) {
+    /** Convenience method to close the current [[com.spotify.scio.ScioContext]]
+     * and display elements from Avro like SCollection */
+    def closeAndDisplay(schema: Schema = null): Unit = {
+      DisplayTapImplicits.ZeppelinAvroTap(materialize(self).waitForResult()).display(schema)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinBQTableSCollection[T: ClassTag](val self: SCollection[T])(implicit ev: T <:< TableRow) extends AnyVal {
+  implicit class ZeppelinBQTableSCollection[T: ClassTag](val self: SCollection[T])
+                                                        (implicit ev: T <:< TableRow) {
+    /** Convenience method to close the current [[com.spotify.scio.ScioContext]]
+     * and display elements from TableRow like SCollection */
+    def closeAndDisplay(schema: TableSchema): Unit = {
+      DisplayTapImplicits.ZeppelinBQTableTap(materialize(self).waitForResult()).display(schema)
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/main/scala/org/apache/zeppelin/scio/DisplayTapImplicits.scala
----------------------------------------------------------------------
diff --git a/scio/src/main/scala/org/apache/zeppelin/scio/DisplayTapImplicits.scala b/scio/src/main/scala/org/apache/zeppelin/scio/DisplayTapImplicits.scala
new file mode 100644
index 0000000..8aafc31
--- /dev/null
+++ b/scio/src/main/scala/org/apache/zeppelin/scio/DisplayTapImplicits.scala
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+import com.google.api.services.bigquery.model.TableSchema
+import com.spotify.scio.bigquery.TableRow
+import com.spotify.scio.io.Tap
+import com.spotify.scio._
+import org.apache.avro.Schema
+import org.apache.avro.generic.GenericRecord
+
+import scala.concurrent.Future
+import scala.reflect.ClassTag
+
+/**
+ * Implicit Zeppelin display helpers for [[Tap]] and [[Future]] of a [[Tap]].
+ */
+object DisplayTapImplicits {
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinTap[T: ClassTag](private val self: Tap[T])(implicit ev: T <:< AnyVal) extends AnyVal {
+  implicit class ZeppelinTap[T: ClassTag](val self: Tap[T])
+                                         (implicit ev: T <:< AnyVal) {
+    /** Convenience method to display [[com.spotify.scio.io.Tap]] of AnyVal. */
+    def display(printer: (T) => String = (e: T) => e.toString): Unit = {
+      DisplayHelpers.displayAnyVal(self.value, printer)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinFutureTap[T: ClassTag](private val self: Future[Tap[T]])(implicit ev: T <:< AnyVal) extends AnyVal {
+  implicit class ZeppelinFutureTap[T: ClassTag](val self: Future[Tap[T]])
+                                               (implicit ev: T <:< AnyVal) {
+    /** Convenience method to display [[Future]] of a [[com.spotify.scio.io.Tap]] of AnyVal. */
+    def waitAndDisplay(printer: (T) => String = (e: T) => e.toString): Unit = {
+      ZeppelinTap(self.waitForResult()).display(printer)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinStringTap[T: ClassTag](private val self: Tap[T])(implicit ev: T <:< String) extends AnyVal {
+  implicit class ZeppelinStringTap[T: ClassTag](val self: Tap[T])
+                                               (implicit ev: T <:< String) {
+    /** Convenience method to display [[com.spotify.scio.io.Tap]] of Strings. */
+    def display(printer: (T) => String = (e: T) => e.toString): Unit = {
+      DisplayHelpers.displayString(self.value, printer)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinFutureStringTap[T: ClassTag](private val self: Tap[T])(implicit ev: T <:< String) extends AnyVal {
+  implicit class ZeppelinFutureStringTap[T: ClassTag](val self: Future[Tap[T]])
+                                                     (implicit ev: T <:< String) {
+    /** Convenience method to display [[Future]] of a [[com.spotify.scio.io.Tap]] of Strings. */
+    def waitAndDisplay(printer: (T) => String = (e: T) => e.toString): Unit = {
+      ZeppelinStringTap(self.waitForResult()).display(printer)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinKVTap[K: ClassTag, V: ClassTag](val self: Tap[(K, V)]) extends AnyVal {
+  implicit class ZeppelinKVTap[K: ClassTag, V: ClassTag](val self: Tap[(K, V)]) {
+    /** Convenience method to display [[com.spotify.scio.io.Tap]] of KV. */
+    def display(): Unit = {
+      DisplayHelpers.displayKV(self.value)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinFutureKVTap[K: ClassTag, V: ClassTag](val self: Future[Tap[(K, V)]]) extends AnyVal {
+  implicit class ZeppelinFutureKVTap[K: ClassTag, V: ClassTag](val self: Future[Tap[(K, V)]]) {
+    /** Convenience method to display [[Future]] of a [[com.spotify.scio.io.Tap]] of KV. */
+    def waitAndDisplay(): Unit = {
+      ZeppelinKVTap(self.waitForResult()).display()
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinProductTap[T: ClassTag](val self: Tap[T])(implicit ev: T <:< Product) extends AnyVal {
+  implicit class ZeppelinProductTap[T: ClassTag](val self: Tap[T])
+                                                (implicit ev: T <:< Product) {
+    /** Convenience method to display [[com.spotify.scio.io.Tap]] of Product. */
+    def display(): Unit = {
+      DisplayHelpers.displayProduct(self.value)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinFutureProductTap[T: ClassTag](val self: Future[Tap[T]])(implicit ev: T <:< Product) extends AnyVal {
+  implicit class ZeppelinFutureProductTap[T: ClassTag](val self: Future[Tap[T]])
+                                                      (implicit ev: T <:< Product) {
+    /** Convenience method to display [[Future]] of a [[com.spotify.scio.io.Tap]] of Product. */
+    def waitAndDisplay(): Unit = {
+      ZeppelinProductTap(self.waitForResult()).display()
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinAvroTap[T: ClassTag](val self: Tap[T])(implicit ev: T <:< GenericRecord) extends AnyVal {
+  implicit class ZeppelinAvroTap[T: ClassTag](val self: Tap[T])
+                                             (implicit ev: T <:< GenericRecord) {
+    /** Convenience method to display [[com.spotify.scio.io.Tap]] of Avro. */
+    def display(schema: Schema = null): Unit = {
+      DisplayHelpers.displayAvro(self.value, schema)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinFutureAvroTap[T: ClassTag](val self: Future[Tap[T]])(implicit ev: T <:< GenericRecord) extends AnyVal {
+  implicit class ZeppelinFutureAvroTap[T: ClassTag](val self: Future[Tap[T]])
+                                                   (implicit ev: T <:< GenericRecord) {
+    /** Convenience method to display [[Future]] of a [[com.spotify.scio.io.Tap]] of Avro. */
+    def waitAndDisplay(schema: Schema = null): Unit = {
+      ZeppelinAvroTap(self.waitForResult()).display(schema)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinBQTableTap[T: ClassTag](val self: Tap[T])(implicit ev: T <:< TableRow) extends AnyVal {
+  implicit class ZeppelinBQTableTap[T: ClassTag](val self: Tap[T])
+                                                (implicit ev: T <:< TableRow) {
+    /** Convenience method to display [[com.spotify.scio.io.Tap]] of BigQuery TableRow. */
+    def display(schema: TableSchema): Unit = {
+      DisplayHelpers.displayBQTableRow(self.value, schema)
+    }
+  }
+
+  // TODO: scala 2.11
+  // implicit class ZeppelinFutureBQTableTap[T: ClassTag](val self: Future[Tap[T]])(implicit ev: T <:< TableRow) extends AnyVal {
+  implicit class ZeppelinFutureBQTableTap[T: ClassTag](val self: Future[Tap[T]])
+                                                      (implicit ev: T <:< TableRow) {
+    /** Convenience method to display [[Future]] of a [[com.spotify.scio.io.Tap]] of BigQuery
+     * TableRow. */
+    def waitAndDisplay(schema: TableSchema): Unit = {
+      ZeppelinBQTableTap(self.waitForResult()).display(schema)
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/main/scala/org/apache/zeppelin/scio/ScioInterpreter.scala
----------------------------------------------------------------------
diff --git a/scio/src/main/scala/org/apache/zeppelin/scio/ScioInterpreter.scala b/scio/src/main/scala/org/apache/zeppelin/scio/ScioInterpreter.scala
new file mode 100644
index 0000000..00d011f
--- /dev/null
+++ b/scio/src/main/scala/org/apache/zeppelin/scio/ScioInterpreter.scala
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+import java.beans.Introspector
+import java.io.PrintStream
+import java.util.Properties
+
+import com.google.cloud.dataflow.sdk.options.{PipelineOptions, PipelineOptionsFactory}
+import com.google.cloud.dataflow.sdk.runners.inprocess.InProcessPipelineRunner
+import com.spotify.scio.repl.{ScioILoop, ScioReplClassLoader}
+import org.apache.zeppelin.interpreter.Interpreter.FormType
+import org.apache.zeppelin.interpreter.util.InterpreterOutputStream
+import org.apache.zeppelin.interpreter.{Interpreter, InterpreterContext, InterpreterResult}
+import org.slf4j.LoggerFactory
+
+import scala.reflect.io.File
+import scala.tools.nsc.GenericRunnerCommand
+import scala.tools.nsc.interpreter.JPrintWriter
+import scala.tools.nsc.util.ClassPath
+
+/**
+ * Scio interpreter for Zeppelin.
+ *
+ * <ul>
+ * <li>{@code zeppelin.scio.argz} - Scio interpreter wide arguments</li>
+ * <li>{@code zeppelin.scio.maxResult} - Max number of SCollection results to display.</li>
+ * </ul>
+ *
+ * <p>
+ * How to use: <br/>
+ * {@code
+ *  $beam.scio
+ *  val (sc, args) = ContextAndArgs(argz)
+ *  sc.parallelize(Seq("foo", "foo", "bar")).countByValue.closeAndDisplay()
+ * }
+ * </p>
+ *
+ */
+
+class ScioInterpreter(property: Properties) extends Interpreter(property) {
+  private val logger = LoggerFactory.getLogger(classOf[ScioInterpreter])
+  private var REPL: ScioILoop = _
+
+  val innerOut = new InterpreterOutputStream(logger)
+
+  override def open(): Unit = {
+    val argz = Option(getProperty("zeppelin.scio.argz"))
+      .getOrElse(s"--runner=${classOf[InProcessPipelineRunner].getSimpleName}")
+      .split(" ")
+      .map(_.trim)
+      .filter(_.nonEmpty)
+      .toList
+
+    // Process command line arguments into a settings object, and use that to start the REPL.
+    // We ignore params we don't care about - hence error function is empty
+    val command = new GenericRunnerCommand(argz, _ => ())
+    val settings = command.settings
+
+    settings.classpath.append(System.getProperty("java.class.path"))
+    settings.usejavacp.value = true
+
+    def classLoaderURLs(cl: ClassLoader): Array[java.net.URL] = cl match {
+      case null => Array()
+      case u: java.net.URLClassLoader => u.getURLs ++ classLoaderURLs(cl.getParent)
+      case _ => classLoaderURLs(cl.getParent)
+    }
+
+    classLoaderURLs(Thread.currentThread().getContextClassLoader)
+      .foreach(u => settings.classpath.append(u.getPath))
+
+    // We have to make sure that scala macros are expandable. paradise plugin has to be added to
+    // -Xplugin paths. In case of assembly - paradise is included in assembly jar - thus we add
+    // itself to -Xplugin. If shell is started from sbt or classpath, paradise jar has to be in
+    // classpath, we find it and add it to -Xplugin.
+
+    val thisJar = this.getClass.getProtectionDomain.getCodeSource.getLocation.getPath
+    // In some cases this may be `target/classes`
+    if(thisJar.endsWith(".jar")) settings.plugin.appendToValue(thisJar)
+
+    ClassPath
+      .split(settings.classpath.value)
+      .find(File(_).name.startsWith("paradise_"))
+      .foreach(settings.plugin.appendToValue)
+
+    // Force the repl to be synchronous, so all cmds are executed in the same thread
+    settings.Yreplsync.value = true
+
+    val jars = ClassPath.split(settings.classpath.value)
+      .flatMap(ClassPath.specToURL)
+      .toArray
+
+    val scioClassLoader = new ScioReplClassLoader(
+      jars ++ classLoaderURLs(Thread.currentThread().getContextClassLoader),
+      null,
+      Thread.currentThread.getContextClassLoader)
+
+    val (dfArgs, _) = parseAndPartitionArgs(argz)
+
+    REPL = new ScioILoop(scioClassLoader, dfArgs, None, new JPrintWriter(innerOut))
+    scioClassLoader.setRepl(REPL)
+
+    // Set classloader chain - expose top level abstract class loader down
+    // the chain to allow for readObject and latestUserDefinedLoader
+    // See https://gist.github.com/harrah/404272
+    settings.embeddedDefaults(scioClassLoader)
+
+    // No need for bigquery dumps
+    sys.props("bigquery.plugin.disable.dump") = true.toString
+
+    REPL.settings_=(settings)
+    REPL.createInterpreter()
+    REPL.interpret(s"""val argz = Array("${argz.mkString("\", \"")}")""")
+    REPL.interpret("import org.apache.zeppelin.scio.DisplaySCollectionImplicits._")
+    REPL.interpret("import org.apache.zeppelin.scio.DisplayTapImplicits._")
+    REPL.interpret("import org.apache.zeppelin.scio.ContextAndArgs")
+  }
+
+  private def parseAndPartitionArgs(args: List[String]): (List[String], List[String]) = {
+    import scala.collection.JavaConverters._
+    // Extract --pattern of all registered derived types of PipelineOptions
+    val classes = PipelineOptionsFactory.getRegisteredOptions.asScala + classOf[PipelineOptions]
+    val optPatterns = classes.flatMap { cls =>
+      cls.getMethods.flatMap { m =>
+        val n = m.getName
+        if ((!n.startsWith("get") && !n.startsWith("is")) ||
+          m.getParameterTypes.nonEmpty || m.getReturnType == classOf[Unit]) None
+        else Some(Introspector.decapitalize(n.substring(if (n.startsWith("is")) 2 else 3)))
+      }.map(s => s"--$s($$|=)".r)
+    }
+
+    // Split cmdlineArgs into 2 parts, optArgs for PipelineOptions and appArgs for Args
+    args.partition(arg => optPatterns.exists(_.findFirstIn(arg).isDefined))
+  }
+
+  override def close(): Unit = {
+    logger.info("Closing Scio interpreter!")
+    REPL.closeInterpreter()
+  }
+
+  override def interpret(code: String, context: InterpreterContext): InterpreterResult = {
+    val paragraphId = context.getParagraphId
+
+    val consoleOut = new PrintStream(innerOut)
+    System.setOut(consoleOut)
+    innerOut.setInterpreterOutput(context.out)
+
+    try {
+      import tools.nsc.interpreter.Results._
+      REPL.interpret(code) match {
+        case Success => {
+          logger.debug(s"Successfully executed `$code` in $paragraphId")
+          new InterpreterResult(InterpreterResult.Code.SUCCESS)
+        }
+        case Error => {
+          logger.error(s"Error executing `$code` in $paragraphId")
+          new InterpreterResult(InterpreterResult.Code.ERROR, "Interpreter error")
+        }
+        case Incomplete => {
+          logger.warn(s"Code `$code` not complete in $paragraphId")
+          new InterpreterResult(InterpreterResult.Code.INCOMPLETE, "Incomplete expression")
+        }
+      }
+    } catch {
+      case e: Exception =>
+        logger.info("Interpreter exception", e)
+        new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage)
+    } finally {
+      innerOut.flush()
+      innerOut.setInterpreterOutput(null)
+      consoleOut.flush()
+    }
+  }
+
+  override def cancel(context: InterpreterContext): Unit = {
+    // not implemented
+  }
+
+  override def getFormType: FormType = FormType.NATIVE
+
+  override def getProgress(context: InterpreterContext): Int = {
+    // not implemented
+    0
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/test/avro/schema.avsc
----------------------------------------------------------------------
diff --git a/scio/src/test/avro/schema.avsc b/scio/src/test/avro/schema.avsc
new file mode 100644
index 0000000..07c3bea
--- /dev/null
+++ b/scio/src/test/avro/schema.avsc
@@ -0,0 +1,12 @@
+{
+  "type": "record",
+  "name": "Account",
+  "namespace": "org.apache.zeppelin.scio.avro",
+  "doc": "Record for an account",
+  "fields": [
+    {"name": "id", "type": "int"},
+    {"name": "type", "type": "string"},
+    {"name": "name", "type": "string"},
+    {"name": "amount", "type": "double"}
+  ]
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/test/java/org/apache/zeppelin/scio/ScioInterpreterTest.java
----------------------------------------------------------------------
diff --git a/scio/src/test/java/org/apache/zeppelin/scio/ScioInterpreterTest.java b/scio/src/test/java/org/apache/zeppelin/scio/ScioInterpreterTest.java
new file mode 100644
index 0000000..bd33886
--- /dev/null
+++ b/scio/src/test/java/org/apache/zeppelin/scio/ScioInterpreterTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio;
+
+import org.apache.zeppelin.display.AngularObjectRegistry;
+import org.apache.zeppelin.display.GUI;
+import org.apache.zeppelin.interpreter.*;
+import org.apache.zeppelin.resource.LocalResourcePool;
+import org.apache.zeppelin.user.AuthenticationInfo;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ScioInterpreterTest {
+  private static ScioInterpreter repl;
+  private static InterpreterGroup intpGroup;
+  private InterpreterContext context;
+
+  private final String newline = "\n";
+
+  private InterpreterContext getNewContext() {
+    return new InterpreterContext("note", "id", "title", "text",
+        new AuthenticationInfo(),
+        new HashMap<String, Object>(),
+        new GUI(),
+        new AngularObjectRegistry(intpGroup.getId(), null),
+        new LocalResourcePool("id"),
+        new LinkedList<InterpreterContextRunner>(),
+        new InterpreterOutput(new InterpreterOutputListener() {
+          @Override
+          public void onAppend(InterpreterOutput out, byte[] line) {}
+          @Override
+          public void onUpdate(InterpreterOutput out, byte[] output) {}
+        }));
+  }
+
+  @Before
+  public void setUp() throws Exception {
+    if (repl == null) {
+      intpGroup = new InterpreterGroup();
+      intpGroup.put("note", new LinkedList<Interpreter>());
+      repl = new ScioInterpreter(new Properties());
+      repl.setInterpreterGroup(intpGroup);
+      intpGroup.get("note").add(repl);
+      repl.open();
+    }
+
+    context = getNewContext();
+  }
+
+  @Test
+  public void testBasicSuccess() {
+    assertEquals(InterpreterResult.Code.SUCCESS,
+        repl.interpret("val a = 1" + newline + "val b = 2", context).code());
+  }
+
+  @Test
+  public void testBasicSyntaxError() {
+    InterpreterResult error = repl.interpret("val a:Int = 'ds'", context);
+    assertEquals(InterpreterResult.Code.ERROR, error.code());
+    assertEquals("Interpreter error", error.message());
+  }
+
+  @Test
+  public void testBasicIncomplete() {
+    InterpreterResult incomplete = repl.interpret("val a = \"\"\"", context);
+    assertEquals(InterpreterResult.Code.INCOMPLETE, incomplete.code());
+    assertEquals("Incomplete expression", incomplete.message());
+  }
+
+  @Test
+  public void testBasicPipeline() {
+    assertEquals(InterpreterResult.Code.SUCCESS,
+        repl.interpret("val (sc, _) = ContextAndArgs(argz)" + newline
+            + "sc.parallelize(1 to 10).closeAndCollect().toList", context).code());
+  }
+
+  @Test
+  public void testBasicMultiStepPipeline() {
+    final StringBuilder code = new StringBuilder();
+    code.append("val (sc, _) = ContextAndArgs(argz)").append(newline)
+        .append("val numbers = sc.parallelize(1 to 10)").append(newline)
+        .append("val results = numbers.closeAndCollect().toList").append(newline)
+        .append("println(results)");
+    assertEquals(InterpreterResult.Code.SUCCESS,
+        repl.interpret(code.toString(), context).code());
+  }
+
+  @Test
+  public void testException() {
+    InterpreterResult exception = repl.interpret("val (sc, _) = ContextAndArgs(argz)" + newline
+        + "throw new Exception(\"test\")", context);
+    assertEquals(InterpreterResult.Code.ERROR, exception.code());
+    assertTrue(exception.message().length() > 0);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/scio/src/test/resources/log4j.properties b/scio/src/test/resources/log4j.properties
new file mode 100644
index 0000000..8daee59
--- /dev/null
+++ b/scio/src/test/resources/log4j.properties
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+log4j.rootLogger = INFO, stdout
+
+log4j.appender.stdout = org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%5p [%d] ({%t} %F[%M]:%L) - %m%n

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/test/scala-2.11/org/apache/zeppelin/scio/DisplayHelpersTestScala211.scala
----------------------------------------------------------------------
diff --git a/scio/src/test/scala-2.11/org/apache/zeppelin/scio/DisplayHelpersTestScala211.scala b/scio/src/test/scala-2.11/org/apache/zeppelin/scio/DisplayHelpersTestScala211.scala
new file mode 100644
index 0000000..729dc87
--- /dev/null
+++ b/scio/src/test/scala-2.11/org/apache/zeppelin/scio/DisplayHelpersTestScala211.scala
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+import org.apache.zeppelin.scio.util.TestUtils
+import org.junit.runner.RunWith
+import org.scalatest.junit.JUnitRunner
+import org.scalatest.{FlatSpec, Matchers}
+
+/**
+ * Scala 2.11 DisplayHelpersTest tests.
+ *
+ * Most tests have test scope implicit imports due to scala 2.10 bug
+ * https://issues.scala-lang.org/browse/SI-3346
+ *
+ * Note: we can't depend on the order of data coming from SCollection.
+ */
+@RunWith(classOf[JUnitRunner]
+class DisplayHelpersTestScala211 extends FlatSpec with Matchers {
+  import TestUtils._
+
+  // -----------------------------------------------------------------------------------------------
+  // Product SCollection Tests
+  // -----------------------------------------------------------------------------------------------
+
+  it should "support SCollection of Case Class of 23" in {
+    import org.apache.zeppelin.scio.DisplaySCollectionImplicits.ZeppelinProductSCollection
+    val tupleHeader = s"$table " + (1 to 22).map(i => s"a$i$tab").mkString + "a23"
+    val o = captureOut {
+      sideEffectWithData(
+        Seq.fill(3)(CC23(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23))) { in =>
+        in.closeAndDisplay()
+      }
+    }
+    o should contain theSameElementsAs (Seq(tupleHeader) ++
+      Seq.fill(3)((1 to 22).map(i => s"$i$tab").mkString + "23"))
+    o.head should be(tupleHeader)
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/zeppelin/blob/f127237f/scio/src/test/scala-2.11/org/apache/zeppelin/scio/TestCCScala211.scala
----------------------------------------------------------------------
diff --git a/scio/src/test/scala-2.11/org/apache/zeppelin/scio/TestCCScala211.scala b/scio/src/test/scala-2.11/org/apache/zeppelin/scio/TestCCScala211.scala
new file mode 100644
index 0000000..eca1205
--- /dev/null
+++ b/scio/src/test/scala-2.11/org/apache/zeppelin/scio/TestCCScala211.scala
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zeppelin.scio
+
+case class CC23(a1: Int, a2: Int, a3: Int, a4: Int, a5: Int, a6: Int, a7: Int, a8: Int, a9: Int,
+                a10: Int, a11: Int, a12: Int, a13: Int, a14: Int, a15: Int, a16: Int, a17: Int,
+                a18: Int, a19: Int, a20: Int, a21: Int, a22: Int, a23: Int)
\ No newline at end of file