Skip to content

Commit

Permalink
resolves #25 support alternative Jupyter kernels (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
ggrossetie authored Sep 22, 2023
1 parent 43e8a4b commit 1dcc8d1
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 1 deletion.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ And here's the result:

![](jupyter-lorenz-notebook.png)

## Document attributes

| Name | Default Value | Mapping |
|----------------------------|---------------|----------------------------------|
| `jupyter-language-name` | `python` | `metadata.language_info.name` |
| `jupyter-language-version` | `3.9.1` | `metadata.language_info.version` |
| `jupyter-kernel-name` | `python3` | `metadata.kernelspec.name` |
| `jupyter-kernel-language` | `python` | `metadata.kernelspec.language` |

**IMPORTANT:** The language name defined in `jupyter-language-name` will be used to decide which AsciiDoc source blocks will be converted to Notebook code cells and which will be converted to Markdown cells.
For instance, if the Jupyter language name is `python` the converter will convert source blocks that have the language `python` to code cells. Source blocks with other languages will be converted as Markdown cells.

## Notebook file format

This converter generates [Jupyter notebooks] using [Notebook file format](https://nbformat.readthedocs.io/en/latest/format_description.html) version 4.4.
17 changes: 16 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class JupyterConverter {
this.ignoredNodes = []
const languageName = node.getAttribute('jupyter-language-name', 'python')
const languageVersion = node.getAttribute('jupyter-language-version', '3.9.1')
const kernelName = node.getAttribute('jupyter-kernel-name', 'python3')
const kernelLanguage = node.getAttribute('jupyter-kernel-language', 'python')
const blocks = node.getBlocks()
const cells = []
let lastCell = {}
Expand Down Expand Up @@ -49,6 +51,10 @@ class JupyterConverter {
language_info: {
name: languageName,
version: languageVersion
},
kernelspec: {
name: kernelName,
language: kernelLanguage
}
},
nbformat: 4,
Expand Down Expand Up @@ -158,7 +164,16 @@ class JupyterConverter {
const lines = node.lines
const source = lines.map((l) => l + '\n')
const language = node.getAttribute('language')
if (language === 'python' || language === 'py') {
const languageName = node.getDocument().getAttribute('jupyter-language-name', 'python')
let languages
if (languageName === 'python' || languageName === 'py') {
languages = ['python', 'py']
} else if (languageName === 'c++' || languageName === 'cpp') {
languages = ['c++', 'cpp']
} else {
languages = [languageName]
}
if (languages.includes(language)) {
return [{
cell_type: 'code',
execution_count: 0,
Expand Down
122 changes: 122 additions & 0 deletions test/converter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,135 @@ describe('Jupyter converter', () => {
const ipynb = JSON.parse(result)
expect(ipynb.metadata.language_info.name).is.equal('python')
expect(ipynb.metadata.language_info.version).is.equal('2.7.10')
expect(ipynb.metadata.kernelspec.name).is.equal('python3')
expect(ipynb.metadata.kernelspec.language).is.equal('python')
expect(ipynb.cells.length).is.equal(32)
const codeCells = ipynb.cells.filter(cell => cell.cell_type === 'code')
expect(codeCells.length).is.equal(21)
expect(codeCells[0].source.join('')).is.equal(`from py2neo import Graph
graph = Graph()
`)
})
it('should configure language with document attributes', async () => {
const result = asciidoctor.convert(`= Hello World
:jupyter-language-name: c++
:jupyter-language-version: 17
`, { backend: 'jupyter' })
expect(result).is.not.empty()
const ipynb = JSON.parse(result)
expect(ipynb.metadata.language_info.name).is.equal('c++')
expect(ipynb.metadata.language_info.version).is.equal('17')
})
it('should configure kernelspec with document attributes', async () => {
const result = asciidoctor.convert(`= Hello World
:jupyter-language-name: c++
:jupyter-language-version: 17
:jupyter-kernel-name: xcpp17
:jupyter-kernel-language: C++17
`, { backend: 'jupyter' })
expect(result).is.not.empty()
const ipynb = JSON.parse(result)
expect(ipynb.metadata.language_info.name).is.equal('c++')
expect(ipynb.metadata.language_info.version).is.equal('17')
expect(ipynb.metadata.kernelspec.name).is.equal('xcpp17')
expect(ipynb.metadata.kernelspec.language).is.equal('C++17')
})
it('should convert source blocks depending on language name (C++)', async () => {
const result = asciidoctor.convert(`= Hello World
:jupyter-language-name: c++
:jupyter-language-version: 17
:jupyter-kernel-name: xcpp17
:jupyter-kernel-language: C++17
.Python
[source,py]
----
print('hello')
----
.C{pp}
[source,cpp]
----
int i=1;
----
`, { backend: 'jupyter' })
expect(result).is.not.empty()
const ipynb = JSON.parse(result)
expect(ipynb.cells.length).is.equal(2)
expect(ipynb.cells[0].cell_type).is.equal('markdown')
expect(ipynb.cells[0].source.join('')).is.equal(`# Hello World
\`\`\`py
print('hello')
\`\`\``)
expect(ipynb.cells[1].cell_type).is.equal('code')
expect(ipynb.cells[1].source.join('')).is.equal(`int i=1;
`)
})
it('should convert source blocks depending on language name (Python)', async () => {
const result = asciidoctor.convert(`= Hello World
:jupyter-language-name: python
:jupyter-language-version: 3.11.5
.Python
[source,py]
----
print('hello')
----
.C{pp}
[source,cpp]
----
int i=1;
----
`, { backend: 'jupyter' })
expect(result).is.not.empty()
const ipynb = JSON.parse(result)
expect(ipynb.cells.length).is.equal(3)
expect(ipynb.cells[0].cell_type).is.equal('markdown')
expect(ipynb.cells[0].source.join('')).is.equal(`# Hello World
`)
expect(ipynb.cells[1].cell_type).is.equal('code')
expect(ipynb.cells[1].source.join('')).is.equal(`print('hello')
`)
expect(ipynb.cells[2].cell_type).is.equal('markdown')
expect(ipynb.cells[2].source.join('')).is.equal(`\`\`\`cpp
int i=1;
\`\`\``)
})
it('should convert source blocks depending on language name (default -> Python)', async () => {
const result = asciidoctor.convert(`= Hello World
.Python
[source,py]
----
print('hello')
----
.C{pp}
[source,cpp]
----
int i=1;
----
`, { backend: 'jupyter' })
expect(result).is.not.empty()
const ipynb = JSON.parse(result)
expect(ipynb.cells.length).is.equal(3)
expect(ipynb.cells[0].cell_type).is.equal('markdown')
expect(ipynb.cells[0].source.join('')).is.equal(`# Hello World
`)
expect(ipynb.cells[1].cell_type).is.equal('code')
expect(ipynb.cells[1].source.join('')).is.equal(`print('hello')
`)
expect(ipynb.cells[2].cell_type).is.equal('markdown')
expect(ipynb.cells[2].source.join('')).is.equal(`\`\`\`cpp
int i=1;
\`\`\``)
})
it('should convert an exercise guide to ipynb', async () => {
const inputFile = path.join(__dirname, 'fixtures', 'intro-neo4j-guides-01.adoc')
Expand Down

0 comments on commit 1dcc8d1

Please sign in to comment.