With Jupytext, text files become Jupyter Notebooks
# %% [markdown]
# # Analysis
# A quick look at the data.
# %%
import pandas as pd
df = pd.read_csv("data.csv")
df.describe()
30+ languages supported. Works in VS Code, PyCharm, Spyder...
# Analysis
A quick look at the data.
```{code-cell} ipython3
import pandas as pd
df = pd.read_csv("data.csv")
df.describe()
```
Best for rich technical docs & Jupyter Book — directives, cross-refs and more.
# Analysis
A quick look at the data.
```python
import pandas as pd
df = pd.read_csv("data.csv")
df.describe()
```
Best for documentation-first notebooks — GitHub Markdown syntax.
---
title: Analysis
---
A quick look at the data.
```{python}
import pandas as pd
df = pd.read_csv("data.csv")
df.describe()
```
For multi-language scientific publishing — Python, R, Julia and more, rendered by the Quarto system.
I see Jupytext as a bridge between communities and tools
.ipynb format is a Rosetta Stone for notebooksJupytext has extensive coverage
auto:percent formatauto:light, auto:nomarker, py:marimo, md:pandoc, py:sphinx, R:spinpy:percent - editable in any IDE or with AI → research and experimentsmd:myst - great for documentation and education → I use it for ITables’ documentationmd:markdown for simple notebooks that look nice on GitHubqmd:quarto for presentations like this one!pixi init && pixi add jupyterlab jupytext
pixi run jupyter lab
pixi add pandas itables
Please write a short
py:percentnotebook to help me try ITables
.py file → Open With → Notebook
Run the notebook, make edits, save → .py is updated accordingly
Make a change in the .py file outside of Jupyter
File → Reload default from disk (🤔 what is default?)
Kernel is still live but outputs are lost!
Create a jupytext.toml file with this content formats="ipynb,py:percent"
Run and save the notebook → saves to .ipynb and .py
Close and re-open, or reload: outputs are still there!
We can still modify the .py file outside of Jupyter
The inputs in the .py file have precedence over the .ipynb file.
wikify: internal Confluence publisher, a precursor to quarto publishipymd and notedown. Great projects, but they did not work well enough for me (Python 2 etc)nbrmd), then realized that more Pythonic formats would be appropriate (nbsrc, .py scripts)Maintainers
There are two of us! Mahendra Paipuri did tremendous work on our JupyterLab extension (the Jupytext Menu)
Advanced Users
I have had very constructive and consistent feedback from some users, some of whom I am glad to meet here for the first time!
Jupyter Maintainers and QuantStack
The community of Jupyter developers has been incredibly helpful, and they helped me ensure compatibility with the major Jupyter updates.
105 contributors so far!
Stable/Production
Jupytext is actively maintained but is fairly stable now
Improve awareness
I do meet many people that have not heard of Jupytext but would find it useful.
Brand new jupytext.org website! Unfortunately I can’t do monthly newsletters like Marimo 😅
Brand
Jupytext is still under my GitHub user name, should we move it to an organization?
TypeScript implementation by QuantStack!! Are Text Notebooks becoming a Jupyter standard? Also, plainb works in web-only contexts like JupyterLite!
.ipynb file is more recent than the .py file, Jupytext will refuse to open the document because the user is at risk of losing an edit. Should not happen but… you edited the .ipynb outside of Jupyter, or git clone was slow?.ipynb files you still have the challenge of merging thempy:percent formatWhile the py:percent format looks (and is) mostly trivial, we do have the following requirements:
.ipynb and the .py file.py file should be correct PythonDetailed features
.py filels, cat or !custom) are also commented out.ipynb!When does the synchronization occur?
Jupyter
Sync happens on load in memory, and is only materialized on disk when saving.
.py, outputs from .ipynb.ipynb and then to .pyCLI
jupytext --sync takes inputs from the newest paired file.
Use --check-source-is-newer to force the file you pass as the source.
VS Code
With the Jupytext Sync extension by Victor Negîrneac, sync happens when either file is saved, using jupytext --sync --check-source-is-newer under the hood.
pre-commit
We also have a pre-commit hook for jupytext --sync!
You need to a) edit only one file or b) change both files in a consistent way.
formats = "ipynb,py:percent"formats = "ipynb,.myst.md:myst"formats = "ipynb,py:percent,md:myst"formats = "notebooks///ipynb,scripts///py:percent"Paired notebooks take the inputs from the most recent text file in the pair, and outputs from the .ipynb file.
Metadata that has been filtered out of the text notebook is also restored from the .ipynb file.
The merging algorithm allocates the outputs and cell metadata to the input cells in a way that resists simple edits, cell moves, and reformatting.
The percent, light, sphinx, markdown, and Rmd formats are fully implemented within Jupytext.
The quarto, pandoc, marimo formats simply call the corresponding tool to achieve the conversion. It’s still useful to have them in Jupytext as it provides the Jupyter integration.
The MyST format is an exception as it is partially implemented in Jupytext - we should probably delegate this entirely to MyST: #1543
Research notebooks
My research notebooks are scratch pads. They might not work anymore in two weeks.
Still, I commit them to a research repo. I use ruff check --fix and ruff format as pre-commit hooks on my .py notebooks to ensure minimal quality checks like no missing variable etc.
Documentation
ITables’ documentation notebooks are subject to
pre-commit ruff checks as abovepyright type checks (hence the md:myst,py:percent pairing)Jupytext’s issue #220 was about implementing a format with outputs.
My target:
.txt, .png, .html files (etc) and they are saved in a folder with the same name as the notebookDid I put too many constraints and ended up with an empty solution set?
plainb landing, and text notebooks supported in JupyterLite and notebook.link!Jupytext, by Marc Wouts. MyST Markdown in Education, Paris, June 17, 2026