-
Notifications
You must be signed in to change notification settings - Fork 517
Expand file tree
/
Copy pathfrontmatter.py
More file actions
84 lines (70 loc) · 3.17 KB
/
frontmatter.py
File metadata and controls
84 lines (70 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"""A YAML and formatted-markdown frontmatter processor"""
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/09_frontmatter.ipynb.
# %% auto #0
__all__ = ['nb_frontmatter', 'FrontmatterProc']
# %% ../nbs/api/09_frontmatter.ipynb #2398f5ef-06d3-4890-8a54-7cf4f81f3894
from .imports import *
from .process import *
from .doclinks import _nbpath2html
from execnb.nbio import *
from fastcore.imports import *
import yaml
# %% ../nbs/api/09_frontmatter.ipynb #6d13ecdb
_RE_FM_BASE=r'''^---\s*
(.*?\S+.*?)
---\s*'''
_re_fm_nb = re.compile(_RE_FM_BASE+'$', flags=re.DOTALL)
_re_fm_md = re.compile(_RE_FM_BASE, flags=re.DOTALL)
# %% ../nbs/api/09_frontmatter.ipynb #1725f3b9
def _fm2dict(s:str, nb=True):
"Load YAML frontmatter into a `dict`"
re_fm = _re_fm_nb if nb else _re_fm_md
match = re_fm.search(s.strip())
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 {}
m = re.search(r'^#\s+(\S.*?)\s*$', s, flags=re.MULTILINE)
if not m: return {}
res = {'title': m.group(1)}
m = re.search(r'^>\s+(\S.*?)\s*$', s, flags=re.MULTILINE)
if m: res['description'] = m.group(1)
r = re.findall(r'^-\s+(\S.*:.*\S)\s*$', s, flags=re.MULTILINE)
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
# %% ../nbs/api/09_frontmatter.ipynb #4ba11b21
def nb_frontmatter(nb):
"Get frontmatter dict from `nb` without modifying cells"
raw = first(c for c in nb.cells if c.cell_type=='raw')
md = first(c for c in nb.cells if c.cell_type=='markdown')
res = _md2dict(md.source) if md else {}
if raw: res.update(_fm2dict(raw.source))
return res
# %% ../nbs/api/09_frontmatter.ipynb #1b5d9d32
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 FrontmatterProc(Processor):
"A YAML and formatted-markdown frontmatter processor"
def begin(self): self.fm = getattr(self.nb, 'frontmatter_', {})
def _update(self, f, cell):
s = cell.get('source')
if not s: return
d = f(s)
if not d: return
self.fm.update(d)
cell.source = None
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
if not hasattr(self.nb, 'path_'):
raise AttributeError('Notebook missing `path_` attribute.\n\nPlease remove any nbdev-related notebook filters '
'from your _quarto.yml file (e.g. `ipynb-filter: [nbdev_filter]`), since they are no '
'longer supported as of nbdev v2.3. See the v2.3 launch post for more information: '
'https://forums.fast.ai/t/upcoming-changes-in-v2-3-edit-now-released/98905.')
self.fm.update({'output-file': _nbpath2html(Path(self.nb.path_)).name})
_insertfm(self.nb, self.fm)