Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Clojure support #193

Merged
merged 5 commits into from
Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Have you always wished Jupyter notebooks were plain text documents? Wished you c

Jupytext can save Jupyter notebooks as
- Markdown and R Markdown documents,
- Julia, Python, R, Bash, Scheme, C++ and q/kdb+ scripts.
- Julia, Python, R, Bash, Scheme, Clojure, C++ and q/kdb+ scripts.

There are multiple ways to use `jupytext`:
- Directly from Jupyter Notebook or JupyterLab. Jupytext provides a _contents manager_ that allows Jupyter to save your notebook to your favorite format (`.py`, `.R`, `.jl`, `.md`, `.Rmd`...) in addition to (or in place of) the traditional `.ipynb` file. The text representation can be edited in your favorite editor. When you're done, refresh the notebook in Jupyter: inputs cells are loaded from the text file, while output cells are reloaded from the `.ipynb` file if present. Refreshing preserves kernel variables, so you can resume your work in the notebook and run the modified cells without having to rerun the notebook in full.
Expand Down Expand Up @@ -347,7 +347,7 @@ The `light` format has:
- Code cells are exported verbatim (except for Jupyter magics, which are commented), and separated with blank lines. Code cells are reconstructed from consistent Python paragraphs (no function, class or multiline comment will be broken).
- Cells that contain more than one Python paragraphs need an explicit start-of-cell delimiter `# +` (`// +` in C++, etc). Cells that have explicit metadata have a cell header `# + {JSON}` where the metadata is represented, in JSON format. The end of cell delimiter is `# -`, and is omitted when followed by another explicit start of cell marker.

The `light` format is currently available for Python, Julia, R, Bash, Scheme, C++ and q/kdb+. Open our sample notebook in the `light` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.lgt.py).
The `light` format is currently available for Python, Julia, R, Bash, Scheme, Clojure, C++ and q/kdb+. Open our sample notebook in the `light` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.lgt.py).

A variation of the `light` format is the `bare` format, with no cell marker at all. Please note that this format will split your code cells on code paragraphs. By default, this format still includes a YAML header - if you prefer to also remove the header, set `"notebook_metadata_filter": "-all"` in the jupytext section of your notebook metadata.

Expand All @@ -368,7 +368,7 @@ where cell type is either omitted (code cells), or `[markdown]` or `[raw]`. The

Percent scripts created by Jupytext have a header with an explicit format information. The format of scripts with no header is inferred automatically: scripts with at least one `# %%` cell are identified as `percent` scripts. Scripts with at least one double percent cell, and an uncommented Jupyter magic command, are identified as `hydrogen` scripts.

The `percent` format is currently available for Python, Julia, R, Bash, Scheme, C++ and q/kdb+. Open our sample notebook in the `percent` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.pct.py).
The `percent` format is currently available for Python, Julia, R, Bash, Scheme, Clojure, C++ and q/kdb+. Open our sample notebook in the `percent` format [here](https://github.com/mwouts/jupytext/blob/master/demo/World%20population.pct.py).

If the `percent` format is your favorite one, add the following to your `.jupyter/jupyter_notebook_config.py` file:
```python
Expand Down
1 change: 1 addition & 0 deletions jupytext/languages.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
'.jl': {'language': 'julia', 'comment': '#'},
'.cpp': {'language': 'c++', 'comment': '//'},
'.ss': {'language': 'scheme', 'comment': ';;'},
'.clj': {'language': 'clojure', 'comment': ';;'},
'.scm': {'language': 'scheme', 'comment': ';;'},
'.sh': {'language': 'bash', 'comment': '#'},
'.q': {'language': 'q', 'comment': '/'}}
Expand Down
261 changes: 261 additions & 0 deletions tests/notebooks/ipynb_clojure/html-demo.ipynb

Large diffs are not rendered by default.

88 changes: 88 additions & 0 deletions tests/notebooks/mirror/ipynb_to_percent/html-demo.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
;; ---
;; jupyter:
;; kernelspec:
;; display_name: Clojure
;; language: clojure
;; name: clojure
;; ---

;; %% [markdown]
;; # Clojupyter Demo
;;
;; This example notebook is from the [Clojupyter](https://github.com/clojupyter/clojupyter/blob/1637f6b2557f01db1e35bae5389bc38522eefe9a/examples/html-demo.ipynb) project.
;; This notebook demonstrates some of the more advanced features of Clojupyter.

;; %% [markdown]
;; ## Displaying HTML
;;
;; To display HTML, you'll need to require a clojupyter helper function to change the cell output

;; %%
(require '[clojupyter.misc.display :as display])

;; %%
(println ">> should print some text")
;; displaying html
(display/hiccup-html
[:ul
[:li "a " [:i "emphatic"] " idea"]
[:li "a " [:b "bold"] " idea"]
[:li "an " [:span {:style "text-decoration: underline;"} "important"] " idea"]])

;; %% [markdown]
;; We can also use this to render SVG:

;; %%
(display/hiccup-html
[:svg {:height 100 :width 100 :xmlns "http://www.w3.org/2000/svg"}
[:circle {:cx 50 :cy 40 :r 40 :fill "red"}]])

;; %% [markdown]
;; ## Adding External Clojure Dependencies
;;
;; You can fetch external Clojure dependcies using the `clojupyter.misc.helper` namespace.

;; %%
(require '[clojupyter.misc.helper :as helper])

;; %%
(helper/add-dependencies '[org.clojure/data.json "0.2.6"])
(require '[clojure.data.json :as json])

;; %%
(json/write-str {:a 1 :b [2, 3] :c "c"})

;; %% [markdown]
;; ## Adding External Javascript Dependency
;;
;; Since you can render arbitrary HTML using `display/hiccup-html`, it's pretty easy to use external Javascript libraries to do things like generate charts. Here's an example using [Highcharts](https://www.highcharts.com/).
;;
;; First, we use a cell to add javascript to the running notebook:

;; %%
(helper/add-javascript "https://code.highcharts.com/highcharts.js")

;; %% [markdown]
;; Now we define a function which takes Clojure data and returns hiccup HTML to display:

;; %%
(defn plot-highchart [highchart-json]
(let [id (str (java.util.UUID/randomUUID))
code (format "Highcharts.chart('%s', %s );" id, (json/write-str highchart-json))]
(display/hiccup-html
[:div [:div {:id id :style {:background-color "red"}}]
[:script code]])))

;; %% [markdown]
;; Now we can make generate interactive plots (try hovering over plot):

;; %%
(def raw-data (map #(+ (* 22 (+ % (Math/random)) 78)) (range)))
(def data-1 (take 500 raw-data))
(def data-2 (take 500 (drop 500 raw-data)))

(plot-highchart {:chart {:type "line"}
:title {:text "Plot of random data"}
:series [{:data data-1} {:data data-2}]})

;; %%
74 changes: 74 additions & 0 deletions tests/notebooks/mirror/ipynb_to_script/html-demo.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
;; ---
;; jupyter:
;; kernelspec:
;; display_name: Clojure
;; language: clojure
;; name: clojure
;; ---

;; # Clojupyter Demo
;;
;; This example notebook is from the [Clojupyter](https://github.com/clojupyter/clojupyter/blob/1637f6b2557f01db1e35bae5389bc38522eefe9a/examples/html-demo.ipynb) project.
;; This notebook demonstrates some of the more advanced features of Clojupyter.

;; ## Displaying HTML
;;
;; To display HTML, you'll need to require a clojupyter helper function to change the cell output

(require '[clojupyter.misc.display :as display])

(println ">> should print some text")
;; displaying html
(display/hiccup-html
[:ul
[:li "a " [:i "emphatic"] " idea"]
[:li "a " [:b "bold"] " idea"]
[:li "an " [:span {:style "text-decoration: underline;"} "important"] " idea"]])

;; We can also use this to render SVG:

(display/hiccup-html
[:svg {:height 100 :width 100 :xmlns "http://www.w3.org/2000/svg"}
[:circle {:cx 50 :cy 40 :r 40 :fill "red"}]])

;; ## Adding External Clojure Dependencies
;;
;; You can fetch external Clojure dependcies using the `clojupyter.misc.helper` namespace.

(require '[clojupyter.misc.helper :as helper])

(helper/add-dependencies '[org.clojure/data.json "0.2.6"])
(require '[clojure.data.json :as json])

(json/write-str {:a 1 :b [2, 3] :c "c"})

;; ## Adding External Javascript Dependency
;;
;; Since you can render arbitrary HTML using `display/hiccup-html`, it's pretty easy to use external Javascript libraries to do things like generate charts. Here's an example using [Highcharts](https://www.highcharts.com/).
;;
;; First, we use a cell to add javascript to the running notebook:

(helper/add-javascript "https://code.highcharts.com/highcharts.js")

;; Now we define a function which takes Clojure data and returns hiccup HTML to display:

(defn plot-highchart [highchart-json]
(let [id (str (java.util.UUID/randomUUID))
code (format "Highcharts.chart('%s', %s );" id, (json/write-str highchart-json))]
(display/hiccup-html
[:div [:div {:id id :style {:background-color "red"}}]
[:script code]])))

;; Now we can make generate interactive plots (try hovering over plot):

;; +
(def raw-data (map #(+ (* 22 (+ % (Math/random)) 78)) (range)))
(def data-1 (take 500 raw-data))
(def data-2 (take 500 (drop 500 raw-data)))

(plot-highchart {:chart {:type "line"}
:title {:text "Plot of random data"}
:series [{:data data-1} {:data data-2}]})
;; -


10 changes: 10 additions & 0 deletions tests/test_mirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ def test_ipynb_to_scheme(nb_file, extension):
assert_conversion_same_as_mirror(nb_file, extension, 'ipynb_to_script')


@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_clojure'))
def test_ipynb_to_clojure(nb_file):
assert_conversion_same_as_mirror(nb_file, 'clj', 'ipynb_to_script')


@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_bash'))
def test_ipynb_to_bash(nb_file):
assert_conversion_same_as_mirror(nb_file, 'sh', 'ipynb_to_script')
Expand Down Expand Up @@ -182,6 +187,11 @@ def test_ipynb_to_scheme_percent(nb_file, extension):
'ipynb_to_percent')


@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_clojure'))
def test_ipynb_to_clojure_percent(nb_file):
assert_conversion_same_as_mirror(nb_file, 'clj:percent', 'ipynb_to_percent')


@pytest.mark.parametrize('nb_file', list_notebooks('ipynb_bash'))
def test_ipynb_to_bash_percent(nb_file):
assert_conversion_same_as_mirror(nb_file, 'sh:percent', 'ipynb_to_percent')
Expand Down
31 changes: 31 additions & 0 deletions tests/test_read_simple_clojure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-

from testfixtures import compare
import jupytext


def test_read_simple_file(script=""";; ---
;; title: Simple file
;; ---

;; Here we have some text
;; And below we have some code

((fn
[]
(println "Hello World")))
"""):
nb = jupytext.reads(script, 'clj')
assert len(nb.cells) == 3
assert nb.cells[0].cell_type == 'raw'
assert nb.cells[0].source == '---\ntitle: Simple file\n---'
assert nb.cells[1].cell_type == 'markdown'
assert nb.cells[1].source == 'Here we have some text\n' \
'And below we have some code'
assert nb.cells[2].cell_type == 'code'
compare(nb.cells[2].source, """((fn
[]
(println "Hello World")))""")

script2 = jupytext.writes(nb, 'clj')
compare(script, script2)