From 508f4eac2e9c9b1481acc9343d154026d022ccf1 Mon Sep 17 00:00:00 2001 From: Marc Wouts Date: Sun, 2 Jun 2024 18:11:44 +0100 Subject: [PATCH 1/4] Allow an empty prefix in format dict --- CHANGELOG.md | 2 ++ src/jupytext/config.py | 4 +++- tests/functional/config/test_config.py | 9 +++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a577ff6a1..09e9b5694 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ Jupytext ChangeLog **Fixed** - We have fixed a typo when `build_jupytext_contents_manager_class` can't be imported ([#1162](https://github.com/mwouts/jupytext/issues/1162)) +- 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 +- Empty prefixes are now allowed in Jupytext format when specified as a dictionary ([#1144](https://github.com/mwouts/jupytext/issues/1144)) 1.16.2 (2024-05-05) diff --git a/src/jupytext/config.py b/src/jupytext/config.py index 81bdfe38f..3b0269b04 100644 --- a/src/jupytext/config.py +++ b/src/jupytext/config.py @@ -398,7 +398,9 @@ def load_jupytext_configuration_file(config_file, stream=None): # formats can be a dict prefix => format if isinstance(config.formats, dict): config.formats = [ - (prefix[:-1] if prefix.endswith("/") else prefix) + "///" + fmt + fmt + if not prefix + else (prefix[:-1] if prefix.endswith("/") else prefix) + "///" + fmt for prefix, fmt in config.formats.items() ] config.formats = short_form_multiple_formats(config.formats) diff --git a/tests/functional/config/test_config.py b/tests/functional/config/test_config.py index 240ba4bc3..8c705622d 100644 --- a/tests/functional/config/test_config.py +++ b/tests/functional/config/test_config.py @@ -158,6 +158,15 @@ def test_load_jupytext_configuration_file(tmpdir, config_file): """, "notebooks///ipynb,scripts///py:percent", ), + ( + """# Pair local notebooks to scripts in 'notebooks_py' and md files in 'notebooks_md' +[formats] +"" = "ipynb" +"notebooks_py" = "py:percent" +"notebooks_md" = "md:myst" +""", + "ipynb,notebooks_py///py:percent,notebooks_md///md:myst", + ), ], ) def test_jupytext_formats(tmpdir, content_toml, formats_short_form): From ce74c51880c9b15df3a7a620b92b83e4f981e6f1 Mon Sep 17 00:00:00 2001 From: Marc Wouts Date: Tue, 9 Jul 2024 20:21:50 +0100 Subject: [PATCH 2/4] Add support for the Go language (#1250) --- CHANGELOG.md | 3 +- docs/languages.md | 1 + src/jupytext/cell_reader.py | 5 + src/jupytext/cell_to_text.py | 14 ++ src/jupytext/languages.py | 5 + src/jupytext/magics.py | 4 + .../inputs/ipynb_go/hello_world_gonb.ipynb | 149 +++++++++++++++++ .../outputs/ipynb_to_Rmd/hello_world_gonb.Rmd | 69 ++++++++ .../ipynb_to_hydrogen/hello_world_gonb.go | 66 ++++++++ .../outputs/ipynb_to_md/hello_world_gonb.md | 69 ++++++++ .../outputs/ipynb_to_myst/hello_world_gonb.md | 69 ++++++++ .../ipynb_to_percent/hello_world_gonb.go | 66 ++++++++ .../ipynb_to_script/hello_world_gonb.go | 60 +++++++ .../simple_notebooks/test_read_simple_go.py | 156 ++++++++++++++++++ .../test_read_simple_percent.py | 51 ++++++ 15 files changed, 786 insertions(+), 1 deletion(-) create mode 100644 tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb create mode 100644 tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd create mode 100644 tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go create mode 100644 tests/data/notebooks/outputs/ipynb_to_md/hello_world_gonb.md create mode 100644 tests/data/notebooks/outputs/ipynb_to_myst/hello_world_gonb.md create mode 100644 tests/data/notebooks/outputs/ipynb_to_percent/hello_world_gonb.go create mode 100644 tests/data/notebooks/outputs/ipynb_to_script/hello_world_gonb.go create mode 100644 tests/functional/simple_notebooks/test_read_simple_go.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e9b5694..df7a4c550 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 055d0905f..7970d82c1 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 ba09b83be..52f4f299f 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 24fe6ea5a..bf40ab3af 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 28133a45e..446cd1a69 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 babda739d..72f77842e 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 000000000..3799ab33d --- /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 000000000..70e15060b --- /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 000000000..7479a8cdc --- /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 000000000..fa24d6b1b --- /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 000000000..6ce0c8c14 --- /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 000000000..c9f8ddc37 --- /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 000000000..ec544af88 --- /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 000000000..26cf2938b --- /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 eea25a5cd..1a5476f44 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) From cda2cb4005b6ff0037ad2097010c0d9f32a0d4bf Mon Sep 17 00:00:00 2001 From: Jerry James Date: Tue, 9 Jul 2024 13:26:04 -0600 Subject: [PATCH 3/4] Fix re.split DeprecationWarning (#1241) --- src/jupytext/cell_metadata.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jupytext/cell_metadata.py b/src/jupytext/cell_metadata.py index d49aa0c03..a9c49a317 100644 --- a/src/jupytext/cell_metadata.py +++ b/src/jupytext/cell_metadata.py @@ -257,7 +257,7 @@ def parse_rmd_options(line): def rmd_options_to_metadata(options, use_runtools=False): """Parse rmd options and return a metadata dictionary""" - options = re.split(r"\s|,", options, 1) + options = re.split(r"\s|,", options, maxsplit=1) # Special case Wolfram Language, which sadly has a space in the language # name. if options[0:2] == ["wolfram", "language"]: From d3d1a3e6c5262811ab285647a1b471f11c760504 Mon Sep 17 00:00:00 2001 From: Marc Wouts Date: Tue, 9 Jul 2024 20:20:27 +0100 Subject: [PATCH 4/4] Deactivate the Quarto tests on the CI for now --- .github/workflows/step_tests-pip.yml | 6 ++++-- CHANGELOG.md | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/step_tests-pip.yml b/.github/workflows/step_tests-pip.yml index 435647143..f4a0625c1 100644 --- a/.github/workflows/step_tests-pip.yml +++ b/.github/workflows/step_tests-pip.yml @@ -40,8 +40,10 @@ jobs: no_markdown-it-py: true - python-version: "3.x" no_kernel: true - - python-version: "3.x" - quarto: true + # TODO: Quarto 1.5.54 introduces a new markdown cell at the + # top of the notebook, see #1255 + # - python-version: "3.x" + # quarto: true steps: - name: Checkout diff --git a/CHANGELOG.md b/CHANGELOG.md index df7a4c550..39dec8dfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ Jupytext ChangeLog - 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)) +**Changed** +- We've had to deactivate the tests on the Quarto format in the CI as the Quarto round trip +might now add a Markdown cell to the notebook ([#1255](https://github.com/mwouts/jupytext/issues/1255)) + 1.16.2 (2024-05-05) -------------------