Skip to content

Commit 8f8effb

Browse files
committed
initial commit
0 parents  commit 8f8effb

File tree

7 files changed

+207
-0
lines changed

7 files changed

+207
-0
lines changed

.github/workflows/CompatHelper.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
name: CompatHelper
2+
on:
3+
schedule:
4+
- cron: 0 0 * * *
5+
jobs:
6+
build:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Pkg.add("CompatHelper")
10+
run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
11+
- name: CompatHelper.main()
12+
run: julia -e 'using CompatHelper; CompatHelper.main()'
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/TagBot.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
name: TagBot
2+
on:
3+
schedule:
4+
- cron: 0 0 * * *
5+
jobs:
6+
TagBot:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: JuliaRegistries/TagBot@v1
10+
with:
11+
token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Manifest.toml

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 vdayanand <[email protected]> and contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Jupyter2Pluto
2+
## convert Jupyter notebook into [Pluto.jl](https://github.com/fonsp/Pluto.jl) notebook
3+
### Quickstart
4+
``` julia
5+
] add http://github.com/vdayanand/Jupyter2Pluto.jl
6+
using Jupyter2Pluto
7+
convert_notebook("sample.ipynb")
8+
```
9+
Pluto notebook `sample.ipynb.jl` will be created in the directory where jupyter file is located

src/Jupyter2Pluto.jl

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
module Jupyter2Pluto
2+
using JSON
3+
using UUIDs
4+
5+
const _notebook_header = "### A Pluto.jl notebook ###"
6+
const _cell_id_delimiter = "# ╔═╡ "
7+
const _order_delimiter = "# ╠═"
8+
const _order_delimiter_folded = "# ╟─"
9+
const _cell_suffix = "\n\n"
10+
11+
export convert_notebook
12+
13+
abstract type JupyterCell end
14+
15+
struct JupyterCodeCell <: JupyterCell
16+
content::Vector{String}
17+
end
18+
struct JupyterMarkdownCell <: JupyterCell
19+
content::String
20+
end
21+
22+
abstract type PlutoCell end
23+
24+
struct PlutoCodeCell <: PlutoCell
25+
cell_id::UUID
26+
content::String
27+
end
28+
29+
struct PlutoBlockCodeCell <: PlutoCell
30+
cell_id::UUID
31+
content::String
32+
end
33+
34+
struct PlutoMarkdownCell <: PlutoCell
35+
cell_id::UUID
36+
content::String
37+
end
38+
39+
function Base.show(io::IO, cell::PlutoCodeCell)
40+
gl = """
41+
$(_cell_id_delimiter)$(cell.cell_id)
42+
$(cell.content)$(_cell_suffix)"""
43+
print(io, gl)
44+
end
45+
46+
function Base.show(io::IO, cell::PlutoBlockCodeCell)
47+
gl = """
48+
$(_cell_id_delimiter)$(cell.cell_id)
49+
begin\n$(cell.content)\nend$(_cell_suffix)"""
50+
print(io, gl)
51+
end
52+
53+
54+
function Base.show(io::IO, cell::PlutoMarkdownCell)
55+
content = replace(cell.content, "\"" => "\\\"")
56+
r = """
57+
$(_cell_id_delimiter)$(cell.cell_id)
58+
md\"
59+
$(content)
60+
\"$(_cell_suffix)"""
61+
print(io, r)
62+
end
63+
64+
function cell_id()
65+
uuid4()
66+
end
67+
68+
function generate_code(pcells::Vector{PlutoCell})
69+
pheader = _notebook_header*"\n\n"
70+
codestring = "$pheader$(join(pcells))$(order_code(pcells))"
71+
return codestring
72+
end
73+
74+
function order_code(pcells::Vector{PlutoCell})
75+
orderstrprefix = "$(_cell_id_delimiter)Cell order:\n"
76+
orderstrprefix *join(order_code.(pcells))
77+
end
78+
79+
function order_code(pcell::PlutoMarkdownCell)
80+
return _order_delimiter_folded*""*string(pcell.cell_id)*"\n"
81+
end
82+
83+
function order_code(pcell::Union{PlutoCodeCell, PlutoBlockCodeCell})
84+
return _order_delimiter*""*string(pcell.cell_id)*"\n"
85+
end
86+
87+
function generate_plutocells(codecell::JupyterCodeCell)
88+
pcells = PlutoCell[]
89+
for content in codecell.content
90+
id = cell_id()
91+
push!(pcells, PlutoCodeCell(id, content))
92+
end
93+
return pcells
94+
end
95+
96+
function PlutoCell(codecell::JupyterCodeCell)
97+
id = cell_id()
98+
if has_multiple_expressions(codecell)
99+
return PlutoBlockCodeCell(id, join(codecell.content))
100+
end
101+
return PlutoCodeCell(id, join(codecell.content))
102+
end
103+
104+
function PlutoCell(codecell::JupyterMarkdownCell)
105+
id = cell_id()
106+
return PlutoMarkdownCell(id, codecell.content)
107+
end
108+
109+
function has_multiple_expressions(codecell::JupyterCodeCell)
110+
expressions = Meta.parse("begin "*join(codecell.content, "\n")*" end").args
111+
filter!(x -> !(x isa LineNumberNode), expressions)
112+
length(expressions) > 1
113+
end
114+
115+
function convert_file(jupyter_file)
116+
jupyter_cells = try
117+
content = JSON.parsefile(jupyter_file)
118+
content["cells"]
119+
catch ex
120+
error("Jupyter notebook parse error")
121+
end
122+
pluto_cells = PlutoCell[]
123+
for cell in jupyter_cells
124+
!haskey(cell, "cell_type") || !haskey(cell,"source") && continue
125+
if cell["cell_type"] == "markdown" && !isempty(cell["source"])
126+
pc = PlutoCell(JupyterMarkdownCell(join(cell["source"])))
127+
push!(pluto_cells, pc)
128+
end
129+
if cell["cell_type"] == "code" && !isempty(cell["source"])
130+
pc = PlutoCell(JupyterCodeCell(cell["source"]))
131+
push!(pluto_cells, pc)
132+
end
133+
end
134+
output = generate_code(pluto_cells)
135+
dest = "$(jupyter_file).jl"
136+
open(dest, "w") do f
137+
write(f, output)
138+
end
139+
dest
140+
end
141+
142+
function convert_notebook(file)
143+
convert_file(file)
144+
end
145+
end # module

test/runtests.jl

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
using Jupyter2Pluto
2+
using Test
3+
4+
@testset "Jupyter2Pluto.jl" begin
5+
# Write your tests here.
6+
end

0 commit comments

Comments
 (0)