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 support for go notebooks #1250

Merged
merged 1 commit into from
Jul 9, 2024
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))


Expand Down
1 change: 1 addition & 0 deletions docs/languages.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Jupytext works with notebooks in any of the following languages:
- Coconut
- F#
- Gnuplot
- Go
- Groovy
- Haskell
- IDL
Expand Down
5 changes: 5 additions & 0 deletions src/jupytext/cell_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 14 additions & 0 deletions src/jupytext/cell_to_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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)
)
Expand Down
5 changes: 5 additions & 0 deletions src/jupytext/languages.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Determine notebook or cell language"""
import re

# Jupyter magic commands that are also languages
_JUPYTER_LANGUAGES = [
Expand Down Expand Up @@ -92,6 +93,7 @@
},
".xsh": {"language": "xonsh", "comment": "#"},
".lua": {"language": "lua", "comment": "--"},
".go": {"language": "go", "comment": "//"},
}

_COMMENT_CHARS = [
Expand All @@ -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):
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 4 additions & 0 deletions src/jupytext/magics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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\.\~\$\\\/\{\}]")

Expand Down
149 changes: 149 additions & 0 deletions tests/data/notebooks/inputs/ipynb_go/hello_world_gonb.ipynb
Original file line number Diff line number Diff line change
@@ -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(`<span style=\"background:pink; color:#111; border-radius: 3px; border: 3px solid orange; font-size: 18px;\">I 🧡 GoNB!</span>`)"
]
},
{
"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
}
69 changes: 69 additions & 0 deletions tests/data/notebooks/outputs/ipynb_to_Rmd/hello_world_gonb.Rmd
Original file line number Diff line number Diff line change
@@ -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(`<span style="background:pink; color:#111; border-radius: 3px; border: 3px solid orange; font-size: 18px;">I 🧡 GoNB!</span>`)
```

```{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")
```
66 changes: 66 additions & 0 deletions tests/data/notebooks/outputs/ipynb_to_hydrogen/hello_world_gonb.go
Original file line number Diff line number Diff line change
@@ -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(`<span style="background:pink; color:#111; border-radius: 3px; border: 3px solid orange; font-size: 18px;">I 🧡 GoNB!</span>`)

// %%
//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")
Loading
Loading