Skip to content

Commit 0687ba8

Browse files
committed
clean_nb: Strip newline from base64-encoded images
1 parent 9535ec0 commit 0687ba8

File tree

4 files changed

+16
-34
lines changed

4 files changed

+16
-34
lines changed

nbdev/_modidx.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
'git_url': 'https://github.com/fastai/nbdev',
77
'lib_path': 'nbdev'},
88
'syms': { 'nbdev.clean': { 'nbdev.clean._add_jupyter_hooks': ('api/clean.html#_add_jupyter_hooks', 'nbdev/clean.py'),
9-
'nbdev.clean._add_trailing_n': ('api/clean.html#_add_trailing_n', 'nbdev/clean.py'),
109
'nbdev.clean._clean_cell': ('api/clean.html#_clean_cell', 'nbdev/clean.py'),
1110
'nbdev.clean._clean_cell_output': ('api/clean.html#_clean_cell_output', 'nbdev/clean.py'),
1211
'nbdev.clean._clean_cell_output_id': ('api/clean.html#_clean_cell_output_id', 'nbdev/clean.py'),

nbdev/clean.py

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@ def _clean_cell_output_id(lines):
5555
return _skip_or_sub(lines) if isinstance(lines,str) else [_skip_or_sub(o) for o in lines]
5656

5757
# %% ../nbs/api/11_clean.ipynb 11
58-
def _add_trailing_n(img):
59-
if not isinstance(img,str): return [ _add_trailing_n(o) for o in img ]
60-
return img + "\n" if img[-1] != "\n" else img
61-
62-
# %% ../nbs/api/11_clean.ipynb 12
6358
def _clean_cell_output(cell, clean_ids):
6459
"Remove `cell` output execution count and optionally ids from text reprs"
6560
outputs = cell.get('outputs', [])
@@ -69,11 +64,11 @@ def _clean_cell_output(cell, clean_ids):
6964
data.pop("application/vnd.google.colaboratory.intrinsic+json", None)
7065
for k in data:
7166
if k.startswith('text') and clean_ids: data[k] = _clean_cell_output_id(data[k])
72-
if k.startswith('image'): data[k] = _add_trailing_n(data[k])
67+
if k.startswith('image') and "svg" not in k: data[k] = data[k].rstrip()
7368
if 'text' in o and clean_ids: o['text'] = _clean_cell_output_id(o['text'])
7469
o.get('metadata', {}).pop('tags', None)
7570

76-
# %% ../nbs/api/11_clean.ipynb 13
71+
# %% ../nbs/api/11_clean.ipynb 12
7772
def _clean_cell(cell, clear_all, allowed_metadata_keys, clean_ids):
7873
"Clean `cell` by removing superfluous metadata or everything except the input if `clear_all`"
7974
if 'execution_count' in cell: cell['execution_count'] = None
@@ -84,7 +79,7 @@ def _clean_cell(cell, clear_all, allowed_metadata_keys, clean_ids):
8479
cell['metadata'] = {} if clear_all else {
8580
k:v for k,v in cell['metadata'].items() if k in allowed_metadata_keys}
8681

87-
# %% ../nbs/api/11_clean.ipynb 14
82+
# %% ../nbs/api/11_clean.ipynb 13
8883
def clean_nb(
8984
nb, # The notebook to clean
9085
clear_all=False, # Remove all cell metadata and cell outputs?
@@ -102,12 +97,12 @@ def clean_nb(
10297
nb['metadata']['kernelspec']['display_name'] = nb["metadata"]["kernelspec"]["name"]
10398
nb['metadata'] = {k:v for k,v in nb['metadata'].items() if k in metadata_keys}
10499

105-
# %% ../nbs/api/11_clean.ipynb 27
100+
# %% ../nbs/api/11_clean.ipynb 26
106101
def _reconfigure(*strms):
107102
for s in strms:
108103
if hasattr(s,'reconfigure'): s.reconfigure(encoding='utf-8')
109104

110-
# %% ../nbs/api/11_clean.ipynb 28
105+
# %% ../nbs/api/11_clean.ipynb 27
111106
def process_write(warn_msg, proc_nb, f_in, f_out=None, disp=False):
112107
if not f_out: f_out = f_in
113108
if isinstance(f_in, (str,Path)): f_in = Path(f_in).open()
@@ -120,15 +115,15 @@ def process_write(warn_msg, proc_nb, f_in, f_out=None, disp=False):
120115
warn(f'{warn_msg}')
121116
warn(e)
122117

123-
# %% ../nbs/api/11_clean.ipynb 29
118+
# %% ../nbs/api/11_clean.ipynb 28
124119
def _nbdev_clean(nb, path=None, clear_all=None):
125120
cfg = get_config(path=path)
126121
clear_all = clear_all or cfg.clear_all
127122
allowed_metadata_keys = cfg.get("allowed_metadata_keys").split()
128123
allowed_cell_metadata_keys = cfg.get("allowed_cell_metadata_keys").split()
129124
return clean_nb(nb, clear_all, allowed_metadata_keys, allowed_cell_metadata_keys, cfg.clean_ids)
130125

131-
# %% ../nbs/api/11_clean.ipynb 30
126+
# %% ../nbs/api/11_clean.ipynb 29
132127
@call_parse
133128
def nbdev_clean(
134129
fname:str=None, # A notebook name or glob to clean
@@ -144,15 +139,15 @@ def nbdev_clean(
144139
if fname is None: fname = get_config().nbs_path
145140
for f in globtastic(fname, file_glob='*.ipynb', skip_folder_re='^[_.]'): _write(f_in=f, disp=disp)
146141

147-
# %% ../nbs/api/11_clean.ipynb 33
142+
# %% ../nbs/api/11_clean.ipynb 32
148143
def clean_jupyter(path, model, **kwargs):
149144
"Clean Jupyter `model` pre save to `path`"
150145
if not (model['type']=='notebook' and model['content']['nbformat']==4): return
151146
get_config.cache_clear() # Allow config changes without restarting Jupyter
152147
jupyter_hooks = get_config(path=path).jupyter_hooks
153148
if jupyter_hooks: _nbdev_clean(model['content'], path=path)
154149

155-
# %% ../nbs/api/11_clean.ipynb 36
150+
# %% ../nbs/api/11_clean.ipynb 35
156151
_pre_save_hook_src = '''
157152
def nbdev_clean_jupyter(**kwargs):
158153
try: from nbdev.clean import clean_jupyter
@@ -162,7 +157,7 @@ def nbdev_clean_jupyter(**kwargs):
162157
c.ContentsManager.pre_save_hook = nbdev_clean_jupyter'''.strip()
163158
_pre_save_hook_re = re.compile(r'c\.(File)?ContentsManager\.pre_save_hook')
164159

165-
# %% ../nbs/api/11_clean.ipynb 37
160+
# %% ../nbs/api/11_clean.ipynb 36
166161
def _add_jupyter_hooks(src, path):
167162
if _pre_save_hook_src in src: return
168163
mod = ast.parse(src)
@@ -180,12 +175,12 @@ def _add_jupyter_hooks(src, path):
180175
if src: src+='\n\n'
181176
return src+_pre_save_hook_src
182177

183-
# %% ../nbs/api/11_clean.ipynb 41
178+
# %% ../nbs/api/11_clean.ipynb 40
184179
def _git_root():
185180
try: return Path(run('git rev-parse --show-toplevel'))
186181
except OSError: return None
187182

188-
# %% ../nbs/api/11_clean.ipynb 44
183+
# %% ../nbs/api/11_clean.ipynb 43
189184
@call_parse
190185
def nbdev_install_hooks():
191186
"Install Jupyter and git hooks to automatically clean, trust, and fix merge conflicts in notebooks"

nbs/api/11_clean.ipynb

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,6 @@
144144
"test_eq(_clean_cell_output_id('foo\\n<function _add2 at 0x7f8252378820>\\nbar'), 'foo\\n<function _add2>\\nbar')"
145145
]
146146
},
147-
{
148-
"cell_type": "code",
149-
"execution_count": null,
150-
"metadata": {},
151-
"outputs": [],
152-
"source": [
153-
"#|exporti\n",
154-
"def _add_trailing_n(img):\n",
155-
" if not isinstance(img,str): return [ _add_trailing_n(o) for o in img ]\n",
156-
" return img + \"\\n\" if img[-1] != \"\\n\" else img"
157-
]
158-
},
159147
{
160148
"cell_type": "code",
161149
"execution_count": null,
@@ -172,7 +160,7 @@
172160
" data.pop(\"application/vnd.google.colaboratory.intrinsic+json\", None)\n",
173161
" for k in data:\n",
174162
" if k.startswith('text') and clean_ids: data[k] = _clean_cell_output_id(data[k])\n",
175-
" if k.startswith('image'): data[k] = _add_trailing_n(data[k])\n",
163+
" if k.startswith('image') and \"svg\" not in k: data[k] = data[k].rstrip()\n",
176164
" if 'text' in o and clean_ids: o['text'] = _clean_cell_output_id(o['text'])\n",
177165
" o.get('metadata', {}).pop('tags', None)"
178166
]
@@ -236,9 +224,9 @@
236224
"outputs": [],
237225
"source": [
238226
"test_nb = read_nb('../../tests/image.ipynb')\n",
239-
"assert test_nb.cells[0].outputs[0].data['image/png'][-1] != \"\\n\" # Make sure it was not converted by acccident\n",
227+
"assert test_nb.cells[0].outputs[0].data['image/png'][-1] == \"\\n\" # Make sure it was not converted by acccident\n",
240228
"clean_nb(test_nb)\n",
241-
"assert test_nb.cells[0].outputs[0].data['image/png'][-1] == \"\\n\""
229+
"assert test_nb.cells[0].outputs[0].data['image/png'][-1] != \"\\n\""
242230
]
243231
},
244232
{

tests/image.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"outputs": [
88
{
99
"data": {
10-
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAE0lEQVR4nGNkaGDACpiwCw9WCQBqCACQJ5at+QAAAABJRU5ErkJggg==",
10+
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAE0lEQVR4nGNkaGDACpiwCw9WCQBqCACQJ5at+QAAAABJRU5ErkJggg==\n",
1111
"text/plain": [
1212
"<PIL.Image.Image image mode=RGB size=8x8>"
1313
]

0 commit comments

Comments
 (0)