import sys
import nbformat
from nbdev.imports import *
from nbdev.process import *
from nbdev.processors import NBProcessor, mk_cell, populate_language, add_show_docs, insert_warning,\
\
strip_ansi, hide_line, filter_stream_, rm_header_dash,
clean_show_doc, exec_show_docs, rm_export, clean_magics, hide_, add_links, strip_hidden_metadatafrom pathlib import Path
import yaml
import re
from execnb.nbio import dict2nb,loads
We need to import required nbdev processors for notebook for minimal rendering.
A few changes required
Nbdev has this notion of path_ of notebook which it adds as metadata on each notebook in FrontmatterProc. Since we work with stdout, it is difficult to know the same when adding an ipynb-filter. So we need to overwrite FrontMatterProc
Not all nbdev processors are required for pure quarto site , so we need to add only the once we use
Imports
FrontMatterProc
=r'''^---\s*
_RE_FM_BASE(.*?\S+.*?)
---\s*'''
= re.compile(_RE_FM_BASE+'$', flags=re.DOTALL)
_re_fm_nb = re.compile(_RE_FM_BASE, flags=re.DOTALL)
_re_fm_md
def _fm2dict(s:str, nb=True):
"Load YAML frontmatter into a `dict`"
= _re_fm_nb if nb else _re_fm_md
re_fm = re_fm.search(s.strip())
match return yaml.safe_load(match.group(1)) if match else {}
def _md2dict(s:str):
"Convert H1 formatted markdown cell to frontmatter dict"
if '#' not in s: return {}
= re.search(r'^#\s+(\S.*?)\s*$', s, flags=re.MULTILINE)
m if not m: return {}
= {'title': m.group(1)}
res = re.search(r'^>\s+(\S.*?)\s*$', s, flags=re.MULTILINE)
m if m: res['description'] = m.group(1)
= re.findall(r'^-\s+(\S.*:.*\S)\s*$', s, flags=re.MULTILINE)
r if r:
try: res.update(yaml.safe_load('\n'.join(r)))
except Exception as e: warn(f'Failed to create YAML dict for:\n{r}\n\n{e}\n')
return res
def _dict2fm(d): return f'---\n{yaml.dump(d)}\n---\n\n'
def _insertfm(nb, fm): nb.cells.insert(0, mk_cell(_dict2fm(fm), 'raw'))
class MyFrontmatterProc(Processor):
"A YAML and formatted-markdown frontmatter processor"
def begin(self): self.fm = getattr(self.nb, 'frontmatter_', {})
def _update(self, f, cell):
= cell.get('source')
s if not s: return
= f(s)
d if not d: return
self.fm.update(d)
= None
cell.source
def cell(self, cell):
if cell.cell_type=='raw': self._update(_fm2dict, cell)
elif cell.cell_type=='markdown' and 'title' not in self.fm: self._update(_md2dict, cell)
def end(self):
self.nb.frontmatter_ = self.fm
if not self.fm: return
self.nb, self.fm) _insertfm(
Filter
def filter_nb():
= [MyFrontmatterProc, populate_language, insert_warning,
procs
strip_ansi, hide_line, filter_stream_, rm_header_dash,
clean_magics, hide_, strip_hidden_metadata]= sys.stdin.read()
nb_txt = dict2nb(loads(nb_txt))
nb = NBProcessor(nb=nb, procs=procs)
nbp
nbp.process()
nbformat.write(nbp.nb, sys.stdout)
filter_nb()
Add filter to _quarto.yml
ipynb-filters:
- nbdev_filter.py
project:
type: website
pre-render: custom2qmd.py
# post-render:
# - notes2site.py
# - app2site.py
preview:
host: '0.0.0.0'
port: 3000
browser: false
# twitter-card: true
Modifying Github Action
For making quarto work with libraries outside python STL we will need to update python environment with additional dependencies. For reasons unknown to me, this modification only works after quarto setup action. Relevant snippet from my publish file
- name: Set up Quarto
uses: quarto-dev/quarto-actions/setup@v2
- name: Install Python and Dependencies
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- run: pip install jupyter
- run: pip install -r requirements.txt
- name: Render and Publish
uses: quarto-dev/quarto-actions/publish@v2
with:
target: netlify
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}