diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e9b569..df7a4c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ Jupytext ChangeLog - Some dependencies of the JupyterLab extensions were updated ([#1243](https://github.com/mwouts/jupytext/issues/1243), [#1245](https://github.com/mwouts/jupytext/issues/1245)) **Added** -- Added support for Lua notebooks ([#1252](https://github.com/mwouts/jupytext/pull/1252)) - thanks to [erentar](https://github.com/erentar) for this contribution +- Lua notebooks are now supported ([#1252](https://github.com/mwouts/jupytext/pull/1252)) - thanks to [erentar](https://github.com/erentar) for this contribution +- Go notebooks are supported too ([#1244](https://github.com/mwouts/jupytext/issues/1244))! Many thanks to [Jan Pfeifer](https://github.com/janpfeifer), author of [GoNB](https://github.com/janpfeifer/gonb), and to [HaveF](https://github.com/HaveF) for their help on this topic. - Empty prefixes are now allowed in Jupytext format when specified as a dictionary ([#1144](https://github.com/mwouts/jupytext/issues/1144)) diff --git a/docs/languages.md b/docs/languages.md index 055d0905..7970d82c 100644 --- a/docs/languages.md +++ b/docs/languages.md @@ -9,6 +9,7 @@ Jupytext works with notebooks in any of the following languages: - Coconut - F# - Gnuplot +- Go - Groovy - Haskell - IDL diff --git a/src/jupytext/cell_reader.py b/src/jupytext/cell_reader.py index ba09b83b..52f4f299 100644 --- a/src/jupytext/cell_reader.py +++ b/src/jupytext/cell_reader.py @@ -555,6 +555,11 @@ def uncomment_code_and_magics(self, lines): else: lines = uncomment(lines) + if self.default_language == "go" and self.language is None: + lines = [ + re.sub(r"^((//\s*)*)(//\s*gonb:%%)", r"\1%%", line) for line in lines + ] + if self.cell_type == "code": return unescape_code_start( lines, self.ext, self.language or self.default_language diff --git a/src/jupytext/cell_to_text.py b/src/jupytext/cell_to_text.py index 24fe6ea5..bf40ab3a 100644 --- a/src/jupytext/cell_to_text.py +++ b/src/jupytext/cell_to_text.py @@ -135,6 +135,13 @@ def cell_to_text(self): if self.cell_type != "code" and not self.metadata and self.use_triple_quotes(): self.metadata["cell_type"] = self.cell_type + # Go notebooks have '%%' or '%% -' magic commands that need to be escaped + if self.default_language == "go" and self.language == "go": + self.source = [ + re.sub(r"^(//\s*)*(%%\s*$|%%\s+-.*$)", r"\1//gonb:\2", line) + for line in self.source + ] + if self.is_code(): return self.code_to_text() @@ -487,6 +494,13 @@ def __init__(self, *args, **kwargs): def cell_to_text(self): """Return the text representation for the cell""" + # Go notebooks have '%%' or '%% -' magic commands that need to be escaped + if self.default_language == "go" and self.language == "go": + self.source = [ + re.sub(r"^(//\s*)*(%%\s*$|%%\s+-.*$)", r"\1//gonb:\2", line) + for line in self.source + ] + active = is_active( self.ext, self.metadata, same_language(self.language, self.default_language) ) diff --git a/src/jupytext/languages.py b/src/jupytext/languages.py index 28133a45..446cd1a6 100644 --- a/src/jupytext/languages.py +++ b/src/jupytext/languages.py @@ -1,4 +1,5 @@ """Determine notebook or cell language""" +import re # Jupyter magic commands that are also languages _JUPYTER_LANGUAGES = [ @@ -92,6 +93,7 @@ }, ".xsh": {"language": "xonsh", "comment": "#"}, ".lua": {"language": "lua", "comment": "--"}, + ".go": {"language": "go", "comment": "//"}, } _COMMENT_CHARS = [ @@ -110,6 +112,7 @@ _JUPYTER_LANGUAGES_LOWER_AND_UPPER = _JUPYTER_LANGUAGES.union( {str.upper(lang) for lang in _JUPYTER_LANGUAGES} ) +_GO_DOUBLE_PERCENT_COMMAND = re.compile(r"^(%%\s*|%%\s+-.*)$") def default_language_from_metadata_and_ext(metadata, ext, pop_main_language=False): @@ -206,6 +209,8 @@ def cell_language(source, default_language, custom_cell_magics): """Return cell language and language options, if any""" if source: line = source[0] + if default_language == "go" and _GO_DOUBLE_PERCENT_COMMAND.match(line): + return None, None if default_language == "csharp": if line.startswith("#!"): lang = line[2:].strip() diff --git a/src/jupytext/magics.py b/src/jupytext/magics.py index babda739..72f77842 100644 --- a/src/jupytext/magics.py +++ b/src/jupytext/magics.py @@ -41,6 +41,10 @@ def get_comment(ext): _MAGIC_FORCE_ESC_RE["csharp"] = re.compile(r"^(// |//)*#![a-zA-Z](.*)//\s*escape") _MAGIC_FORCE_ESC_RE["csharp"] = re.compile(r"^(// |//)*#![a-zA-Z](.*)//\s*noescape") +# Go magics might start with % or ! or !* +# (in addition, Go NB might use %% or %% -, see "_GO_DOUBLE_PERCENT_COMMAND") +_MAGIC_RE["go"] = re.compile(r"^(// |//)*(!|!\*|%|%%|%%%)[a-zA-Z]") + # Commands starting with a question or exclamation mark have to be escaped _PYTHON_HELP_OR_BASH_CMD = re.compile(r"^\s*(# |#)*\s*(\?|!)\s*[A-Za-z\.\~\$\\\/\{\}]") diff --git a/tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb b/tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb new file mode 100644 index 00000000..3799ab33 --- /dev/null +++ b/tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb @@ -0,0 +1,149 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8795db3a-af9a-4f03-a68d-019330861b54", + "metadata": {}, + "source": [ + "A notebook that use [GoNB](https://github.com/janpfeifer/gonb)" + ] + }, + { + "cell_type": "markdown", + "id": "50a2fb21-01b3-46d0-9951-f9a1301a85ca", + "metadata": {}, + "source": [ + "the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75d8418d-a918-4cc8-b42e-384db01f21ae", + "metadata": {}, + "outputs": [], + "source": [ + "func main() {\n", + " fmt.Printf(\"Hello World!\")\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3620f46f-efd5-4454-bc29-418297012ce9", + "metadata": {}, + "outputs": [], + "source": [ + "%%\n", + "fmt.Printf(\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "id": "7fed4a43", + "metadata": {}, + "source": [ + "%% --who=world can pass flags to main func" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "473e2d02", + "metadata": {}, + "outputs": [], + "source": [ + "import (\n", + " \"flag\"\n", + " \"fmt\"\n", + ")\n", + "\n", + "var flagWho = flag.String(\"who\", \"\", \"Your name!\")\n", + "\n", + "%% --who=world\n", + "fmt.Printf(\"Hello %s!\\n\", *flagWho)" + ] + }, + { + "cell_type": "markdown", + "id": "b8e8b4ae", + "metadata": {}, + "source": [ + "%args also can pass flags" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "348efbe1", + "metadata": {}, + "outputs": [], + "source": [ + "%args --who=Wally\n", + "\n", + "func main() {\n", + " flag.Parse()\n", + " fmt.Printf(\"Where is %s?\", *flagWho)\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82f4bb1f-3311-4fca-8025-c54c0305dc64", + "metadata": {}, + "outputs": [], + "source": [ + "import \"github.com/janpfeifer/gonb/gonbui\"\n", + "\n", + "%%\n", + "gonbui.DisplayHtml(`I 🧡 GoNB!`)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a5584ff-f346-45cf-95c1-a3e3b7146c6c", + "metadata": {}, + "outputs": [], + "source": [ + "%%\n", + "gonbui.DisplayMarkdown(\"#### Objective\\n\\n1. Have fun coding **Go**;\\n1. Profit...\\n\"+\n", + " `$$f(x) = \\int_{-\\infty}^{\\infty} e^{-x^2} dx$$`)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "de996381-d92c-4ce6-a135-50cf39288aa1", + "metadata": {}, + "outputs": [], + "source": [ + "func init_a() {\n", + " fmt.Println(\"init_a\")\n", + "}\n", + "%%\n", + "fmt.Println(\"main\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Go (gonb)", + "language": "go", + "name": "gonb" + }, + "language_info": { + "codemirror_mode": "", + "file_extension": ".go", + "mimetype": "", + "name": "go", + "nbconvert_exporter": "", + "pygments_lexer": "", + "version": "go1.21.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd b/tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd new file mode 100644 index 00000000..70e15060 --- /dev/null +++ b/tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd @@ -0,0 +1,69 @@ +--- +jupyter: + kernelspec: + display_name: Go (gonb) + language: go + name: gonb +--- + +A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + + +the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +```{go} +func main() { + fmt.Printf("Hello World!") +} +``` + +```{go} +%% +fmt.Printf("Hello World!") +``` + +%% --who=world can pass flags to main func + +```{go} +import ( + "flag" + "fmt" +) + +var flagWho = flag.String("who", "", "Your name!") + +%% --who=world +fmt.Printf("Hello %s!\n", *flagWho) +``` + +%args also can pass flags + +```{go} +// %args --who=Wally + +func main() { + flag.Parse() + fmt.Printf("Where is %s?", *flagWho) +} +``` + +```{go} +import "github.com/janpfeifer/gonb/gonbui" + +%% +gonbui.DisplayHtml(`I 🧡 GoNB!`) +``` + +```{go} +%% +gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+ + `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`) +``` + +```{go} +func init_a() { + fmt.Println("init_a") +} +%% +fmt.Println("main") +``` diff --git a/tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go b/tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go new file mode 100644 index 00000000..7479a8cd --- /dev/null +++ b/tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go @@ -0,0 +1,66 @@ +// -*- coding: utf-8 -*- +// --- +// jupyter: +// kernelspec: +// display_name: Go (gonb) +// language: go +// name: gonb +// --- + +// %% [markdown] +// A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + +// %% [markdown] +// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +// %% +func main() { + fmt.Printf("Hello World!") +} + +// %% +//gonb:%% +fmt.Printf("Hello World!") + +// %% [markdown] +// //gonb:%% --who=world can pass flags to main func + +// %% +import ( + "flag" + "fmt" +) + +var flagWho = flag.String("who", "", "Your name!") + +//gonb:%% --who=world +fmt.Printf("Hello %s!\n", *flagWho) + +// %% [markdown] +// %args also can pass flags + +// %% +%args --who=Wally + +func main() { + flag.Parse() + fmt.Printf("Where is %s?", *flagWho) +} + +// %% +import "github.com/janpfeifer/gonb/gonbui" + +//gonb:%% +gonbui.DisplayHtml(`I 🧡 GoNB!`) + +// %% +//gonb:%% +gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+ + `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`) + +// %% +func init_a() { + fmt.Println("init_a") +} +//gonb:%% +fmt.Println("main") diff --git a/tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md b/tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md new file mode 100644 index 00000000..fa24d6b1 --- /dev/null +++ b/tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md @@ -0,0 +1,69 @@ +--- +jupyter: + kernelspec: + display_name: Go (gonb) + language: go + name: gonb +--- + +A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + + +the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +```go +func main() { + fmt.Printf("Hello World!") +} +``` + +```go +%% +fmt.Printf("Hello World!") +``` + +%% --who=world can pass flags to main func + +```go +import ( + "flag" + "fmt" +) + +var flagWho = flag.String("who", "", "Your name!") + +%% --who=world +fmt.Printf("Hello %s!\n", *flagWho) +``` + +%args also can pass flags + +```go +%args --who=Wally + +func main() { + flag.Parse() + fmt.Printf("Where is %s?", *flagWho) +} +``` + +```go +import "github.com/janpfeifer/gonb/gonbui" + +%% +gonbui.DisplayHtml(`I 🧡 GoNB!`) +``` + +```go +%% +gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+ + `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`) +``` + +```go +func init_a() { + fmt.Println("init_a") +} +%% +fmt.Println("main") +``` diff --git a/tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md b/tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md new file mode 100644 index 00000000..6ce0c8c1 --- /dev/null +++ b/tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md @@ -0,0 +1,69 @@ +--- +kernelspec: + display_name: Go (gonb) + language: go + name: gonb +--- + +A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + ++++ + +the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +```{code-cell} +func main() { + fmt.Printf("Hello World!") +} +``` + +```{code-cell} +%% +fmt.Printf("Hello World!") +``` + +%% --who=world can pass flags to main func + +```{code-cell} +import ( + "flag" + "fmt" +) + +var flagWho = flag.String("who", "", "Your name!") + +%% --who=world +fmt.Printf("Hello %s!\n", *flagWho) +``` + +%args also can pass flags + +```{code-cell} +%args --who=Wally + +func main() { + flag.Parse() + fmt.Printf("Where is %s?", *flagWho) +} +``` + +```{code-cell} +import "github.com/janpfeifer/gonb/gonbui" + +%% +gonbui.DisplayHtml(`I 🧡 GoNB!`) +``` + +```{code-cell} +%% +gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+ + `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`) +``` + +```{code-cell} +func init_a() { + fmt.Println("init_a") +} +%% +fmt.Println("main") +``` diff --git a/tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go b/tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go new file mode 100644 index 00000000..c9f8ddc3 --- /dev/null +++ b/tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go @@ -0,0 +1,66 @@ +// -*- coding: utf-8 -*- +// --- +// jupyter: +// kernelspec: +// display_name: Go (gonb) +// language: go +// name: gonb +// --- + +// %% [markdown] +// A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + +// %% [markdown] +// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +// %% +func main() { + fmt.Printf("Hello World!") +} + +// %% +//gonb:%% +fmt.Printf("Hello World!") + +// %% [markdown] +// //gonb:%% --who=world can pass flags to main func + +// %% +import ( + "flag" + "fmt" +) + +var flagWho = flag.String("who", "", "Your name!") + +//gonb:%% --who=world +fmt.Printf("Hello %s!\n", *flagWho) + +// %% [markdown] +// %args also can pass flags + +// %% +// %args --who=Wally + +func main() { + flag.Parse() + fmt.Printf("Where is %s?", *flagWho) +} + +// %% +import "github.com/janpfeifer/gonb/gonbui" + +//gonb:%% +gonbui.DisplayHtml(`I 🧡 GoNB!`) + +// %% +//gonb:%% +gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+ + `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`) + +// %% +func init_a() { + fmt.Println("init_a") +} +//gonb:%% +fmt.Println("main") diff --git a/tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go b/tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go new file mode 100644 index 00000000..ec544af8 --- /dev/null +++ b/tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go @@ -0,0 +1,60 @@ +// -*- coding: utf-8 -*- +// --- +// jupyter: +// kernelspec: +// display_name: Go (gonb) +// language: go +// name: gonb +// --- + +// A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + +// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +func main() { + fmt.Printf("Hello World!") +} + +//gonb:%% +fmt.Printf("Hello World!") + +// //gonb:%% --who=world can pass flags to main func + +// + +import ( + "flag" + "fmt" +) + +var flagWho = flag.String("who", "", "Your name!") + +//gonb:%% --who=world +fmt.Printf("Hello %s!\n", *flagWho) +// - + +// // %args also can pass flags + +// + +// %args --who=Wally + +func main() { + flag.Parse() + fmt.Printf("Where is %s?", *flagWho) +} + +// + +import "github.com/janpfeifer/gonb/gonbui" + +//gonb:%% +gonbui.DisplayHtml(`I 🧡 GoNB!`) +// - + +//gonb:%% +gonbui.DisplayMarkdown("#### Objective\n\n1. Have fun coding **Go**;\n1. Profit...\n"+ + `$$f(x) = \int_{-\infty}^{\infty} e^{-x^2} dx$$`) + +func init_a() { + fmt.Println("init_a") +} +//gonb:%% +fmt.Println("main") diff --git a/tests/functional/simple_notebooks/test_read_simple_go.py b/tests/functional/simple_notebooks/test_read_simple_go.py new file mode 100644 index 00000000..26cf2938 --- /dev/null +++ b/tests/functional/simple_notebooks/test_read_simple_go.py @@ -0,0 +1,156 @@ +import jupytext +from jupytext.compare import compare + + +def test_read_simple_file( + go="""// -*- coding: utf-8 -*- +// --- +// jupyter: +// kernelspec: +// display_name: Go (gonb) +// language: go +// name: gonb +// --- + +// A notebook that use [GoNB](https://github.com/janpfeifer/gonb) + +// the code below comes from [tutorial.ipynb](https://github.com/janpfeifer/gonb/blob/main/examples/tutorial.ipynb) + +func main() { + fmt.Printf("Hello World!") +} +""", +): + nb = jupytext.reads(go, "go:light") + assert len(nb.cells) == 3 + assert nb.cells[0].cell_type == "markdown" + assert nb.cells[1].cell_type == "markdown" + assert nb.cells[2].cell_type == "code" + + +def test_read_go_notebook_with_percent_percent_and_arguments( + go="""// %% [markdown] +// # Square Function +// +// Defines a function $f(x) = x^2$ + +// %% +func Square(x float64) float64 { + return x*x +} + +// %% [markdown] +// # Examples +// +// ## Example A: $x = 3$ + +// %% +var x = flag.Float64("x", 0.0, "value of x to feed f(x)") + +//gonb:%% -x=3 +fmt.Printf("Square(%g)=%g\n", *x, Square(*x)) + +// %% [markdown] +// ## Example B: $x = 4$ + +// %% +//gonb:%% -x=4 +fmt.Printf("Square(%g)=%g\n", *x, Square(*x)) +""", +): + nb = jupytext.reads(go, "go") + for cell in nb.cells: + assert "gonb" not in cell.source, cell.source + + go2 = jupytext.writes(nb, "go") + compare(go2, go) + + +def test_read_go_notebook_with_magic_main( + go="""// %% +package square + +// %% [markdown] +// # Defining a $x^2$ function +// It returns x*x. + +// %% +func Square(x float64) float64 { + return x * x +} + +// %% [markdown] +// # Examples +// +// ## Example A: $x = 3$ + +// %% +var x = flag.Float64("x", 0.0, "Value of x") + +func example() { + fmt.Printf("Square(%g)=%g\n", *x, Square(*x)) +} +// %main example -x=3 + +// %% [markdown] +// ## Example B: $x = 4$ + +// %% +// %main example -x=4 +""", +): + nb = jupytext.reads(go, "go") + for cell in nb.cells: + assert "gonb" not in cell.source, cell.source + + go2 = jupytext.writes(nb, "go") + compare(go2, go) + + +def test_commented_magic( + go="""// %% +// This is a commented magic +// //gonb:%% + +// %% [markdown] +// This is a commented magic in a markdown cell +// // //gonb:%% +""", +): + nb = jupytext.reads(go, "go") + assert len(nb.cells) == 2 + assert nb.cells[0].cell_type == "code" + assert ( + nb.cells[0].source + == """// This is a commented magic +// %%""" + ) + assert nb.cells[1].cell_type == "markdown" + assert ( + nb.cells[1].source + == """This is a commented magic in a markdown cell +// %%""" + ) + go2 = jupytext.writes(nb, "go") + compare(go2, go) + + +def test_magic_commands_are_commented( + go="""// %% +// !*rm -f go.work && go work init && go work use . ${HOME}/Projects/gopjrt +// %goworkfix +// %env LD_LIBRARY_PATH=/usr/local/lib +""", +): + nb = jupytext.reads(go, "go:percent") + assert len(nb.cells) == 1 + assert nb.cells[0].cell_type == "code" + assert ( + nb.cells[0].source + == """!*rm -f go.work && go work init && go work use . ${HOME}/Projects/gopjrt +%goworkfix +%env LD_LIBRARY_PATH=/usr/local/lib""" + ) + + go2 = jupytext.writes(nb, "go") + compare(go2, go) diff --git a/tests/functional/simple_notebooks/test_read_simple_percent.py b/tests/functional/simple_notebooks/test_read_simple_percent.py index eea25a5c..1a5476f4 100644 --- a/tests/functional/simple_notebooks/test_read_simple_percent.py +++ b/tests/functional/simple_notebooks/test_read_simple_percent.py @@ -555,3 +555,54 @@ def test_cell_marker_has_same_indentation_as_code( compare_notebooks(nb_actual, nb_expected) text_actual = jupytext.writes(nb_actual, fmt="py:percent") compare(text_actual, text) + + +@pytest.mark.parametrize("space_in_gonb", [False, True]) +def test_read_simple_gonb_cell_with_double_percent( + space_in_gonb, + go_percent="""// --- +// jupyter: +// kernelspec: +// display_name: Go (gonb) +// language: go +// name: gonb +// --- + +// %% +//gonb:%% +fmt.Printf("Hello World!") +""", +): + """The cell marker should have the same indentation as the first code line. See issue #562""" + if space_in_gonb: + go_percent = go_percent.replace("//gonb:%%", "// gonb:%%") + nb = jupytext.reads(go_percent, fmt="go:percent") + assert len(nb.cells) == 1 + (cell,) = nb.cells + assert cell.cell_type == "code", cell.cell_type + assert ( + cell.source + == """%% +fmt.Printf("Hello World!")""" + ) + + +def test_write_simple_gonb_cell_with_double_percent( + no_jupytext_version_number, + go_percent="""// --- +// jupyter: +// kernelspec: +// display_name: Go (gonb) +// language: go +// name: gonb +// --- + +// %% +//gonb:%% +fmt.Printf("Hello World!") +""", +): + """The cell marker should have the same indentation as the first code line. See issue #562""" + nb = jupytext.reads(go_percent, fmt="go:percent") + go = jupytext.writes(nb, fmt="go:percent") + compare(go, go_percent)