Skip to content

Commit 8e2a05d

Browse files
committed
attempt to modularise
1 parent bc39a51 commit 8e2a05d

File tree

7 files changed

+117
-110
lines changed

7 files changed

+117
-110
lines changed

LICENSE.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Copyright (c) 2015 Min RK, Florian Rathgeber, Michael McNeil Forbes
2+
2019 Casper da Costa-Luis
23

34
Permission is hereby granted, free of charge, to any person obtaining
45
a copy of this software and associated documentation files (the

nbstripout/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from nbstripout import install, uninstall, status, main
2+
from utils import pop_recursive, strip_output

nbstripout.py nbstripout/nbstripout.py

+2-100
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@
9090
from argparse import ArgumentParser, RawDescriptionHelpFormatter
9191
import io
9292
import sys
93+
from .utils import pop_recursive, strip_output
94+
__all__ = ["install", "uninstall", "status", "main"]
9395

9496
input_stream = None
9597
if sys.version_info < (3, 0):
@@ -132,106 +134,6 @@ def write(nb, f):
132134
return current.write(nb, f, 'json')
133135

134136

135-
def _cells(nb):
136-
"""Yield all cells in an nbformat-insensitive manner"""
137-
if nb.nbformat < 4:
138-
for ws in nb.worksheets:
139-
for cell in ws.cells:
140-
yield cell
141-
else:
142-
for cell in nb.cells:
143-
yield cell
144-
145-
146-
def pop_recursive(d, key, default=None):
147-
"""dict.pop(key) where `key` is a `.`-delimited list of nested keys.
148-
149-
>>> d = {'a': {'b': 1, 'c': 2}}
150-
>>> pop_recursive(d, 'a.c')
151-
2
152-
>>> d
153-
{'a': {'b': 1}}
154-
"""
155-
nested = key.split('.')
156-
current = d
157-
for k in nested[:-1]:
158-
if hasattr(current, 'get'):
159-
current = current.get(k, {})
160-
else:
161-
return default
162-
if not hasattr(current, 'pop'):
163-
return default
164-
return current.pop(nested[-1], default)
165-
166-
167-
def strip_output(nb, keep_output, keep_count, extra_keys=''):
168-
"""
169-
Strip the outputs, execution count/prompt number and miscellaneous
170-
metadata from a notebook object, unless specified to keep either the outputs
171-
or counts.
172-
173-
`extra_keys` could be 'metadata.foo cell.metadata.bar metadata.baz'
174-
"""
175-
extra_keys = extra_keys.split()
176-
keys = {'metadata': [], 'cell': {'metadata': []}}
177-
for key in extra_keys:
178-
if key.startswith('metadata.'):
179-
keys['metadata'].append(key[len('metadata.'):])
180-
elif key.startswith('cell.metadata.'):
181-
keys['cell']['metadata'].append(key[len('cell.metadata.'):])
182-
else:
183-
sys.stderr.write('ignoring extra key `%s`' % key)
184-
185-
nb.metadata.pop('signature', None)
186-
nb.metadata.pop('widgets', None)
187-
for field in keys['metadata']:
188-
pop_recursive(nb.metadata, field)
189-
190-
for cell in _cells(nb):
191-
192-
keep_output_this_cell = keep_output
193-
194-
# Keep the output for these cells, but strip count and metadata
195-
if cell.metadata.get('init_cell') or cell.metadata.get('keep_output'):
196-
keep_output_this_cell = True
197-
198-
# Remove the outputs, unless directed otherwise
199-
if 'outputs' in cell:
200-
201-
# Default behavior strips outputs. With all outputs stripped,
202-
# there are no counts to keep and keep_count is ignored.
203-
if not keep_output_this_cell:
204-
cell['outputs'] = []
205-
206-
# If keep_output_this_cell, but not keep_count, strip the counts
207-
# from the output.
208-
if keep_output_this_cell and not keep_count:
209-
for output in cell['outputs']:
210-
if 'execution_count' in output:
211-
output['execution_count'] = None
212-
213-
# If keep_output_this_cell and keep_count, do nothing.
214-
215-
# Remove the prompt_number/execution_count, unless directed otherwise
216-
if 'prompt_number' in cell and not keep_count:
217-
cell['prompt_number'] = None
218-
if 'execution_count' in cell and not keep_count:
219-
cell['execution_count'] = None
220-
221-
# Always remove this metadata
222-
for output_style in ['collapsed', 'scrolled']:
223-
if output_style in cell.metadata:
224-
cell.metadata[output_style] = False
225-
if 'metadata' in cell:
226-
for field in ['collapsed', 'scrolled', 'ExecuteTime']:
227-
cell.metadata.pop(field, None)
228-
for (extra, fields) in keys['cell'].items():
229-
if extra in cell:
230-
for field in fields:
231-
pop_recursive(getattr(cell, extra), field)
232-
return nb
233-
234-
235137
def install(attrfile=None):
236138
"""Install the git filter and set the git attributes."""
237139
from os import name, path

nbstripout/utils.py

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#!/usr/bin/env python
2+
__all__ = ["pop_recursive", "strip_output"]
3+
4+
5+
def pop_recursive(d, key, default=None):
6+
"""dict.pop(key) where `key` is a `.`-delimited list of nested keys.
7+
8+
>>> d = {'a': {'b': 1, 'c': 2}}
9+
>>> pop_recursive(d, 'a.c')
10+
2
11+
>>> d
12+
{'a': {'b': 1}}
13+
"""
14+
nested = key.split('.')
15+
current = d
16+
for k in nested[:-1]:
17+
if hasattr(current, 'get'):
18+
current = current.get(k, {})
19+
else:
20+
return default
21+
if not hasattr(current, 'pop'):
22+
return default
23+
return current.pop(nested[-1], default)
24+
25+
26+
def _cells(nb):
27+
"""Yield all cells in an nbformat-insensitive manner"""
28+
if nb.nbformat < 4:
29+
for ws in nb.worksheets:
30+
for cell in ws.cells:
31+
yield cell
32+
else:
33+
for cell in nb.cells:
34+
yield cell
35+
36+
37+
def strip_output(nb, keep_output, keep_count, extra_keys=''):
38+
"""
39+
Strip the outputs, execution count/prompt number and miscellaneous
40+
metadata from a notebook object, unless specified to keep either the outputs
41+
or counts.
42+
43+
`extra_keys` could be 'metadata.foo cell.metadata.bar metadata.baz'
44+
"""
45+
extra_keys = extra_keys.split()
46+
keys = {'metadata': [], 'cell': {'metadata': []}}
47+
for key in extra_keys:
48+
if key.startswith('metadata.'):
49+
keys['metadata'].append(key[len('metadata.'):])
50+
elif key.startswith('cell.metadata.'):
51+
keys['cell']['metadata'].append(key[len('cell.metadata.'):])
52+
else:
53+
sys.stderr.write('ignoring extra key `%s`' % key)
54+
55+
nb.metadata.pop('signature', None)
56+
nb.metadata.pop('widgets', None)
57+
for field in keys['metadata']:
58+
pop_recursive(nb.metadata, field)
59+
60+
for cell in _cells(nb):
61+
keep_output_this_cell = keep_output
62+
63+
# Keep the output for these cells, but strip count and metadata
64+
if cell.metadata.get('init_cell') or cell.metadata.get('keep_output'):
65+
keep_output_this_cell = True
66+
67+
# Remove the outputs, unless directed otherwise
68+
if 'outputs' in cell:
69+
70+
# Default behavior strips outputs. With all outputs stripped,
71+
# there are no counts to keep and keep_count is ignored.
72+
if not keep_output_this_cell:
73+
cell['outputs'] = []
74+
75+
# If keep_output_this_cell, but not keep_count, strip the counts
76+
# from the output.
77+
if keep_output_this_cell and not keep_count:
78+
for output in cell['outputs']:
79+
if 'execution_count' in output:
80+
output['execution_count'] = None
81+
82+
# If keep_output_this_cell and keep_count, do nothing.
83+
84+
# Remove the prompt_number/execution_count, unless directed otherwise
85+
if 'prompt_number' in cell and not keep_count:
86+
cell['prompt_number'] = None
87+
if 'execution_count' in cell and not keep_count:
88+
cell['execution_count'] = None
89+
90+
# Always remove this metadata
91+
for output_style in ['collapsed', 'scrolled']:
92+
if output_style in cell.metadata:
93+
cell.metadata[output_style] = False
94+
if 'metadata' in cell:
95+
for field in ['collapsed', 'scrolled', 'ExecuteTime']:
96+
cell.metadata.pop(field, None)
97+
for (extra, fields) in keys['cell'].items():
98+
if extra in cell:
99+
for field in fields:
100+
pop_recursive(getattr(cell, extra), field)
101+
return nb

setup.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from setuptools import setup
1+
from setuptools import setup, find_packages
22

33
with open('README.rst') as f:
44
long_description = f.read()
@@ -32,10 +32,11 @@
3232

3333
description='Strips outputs from Jupyter and IPython notebooks',
3434
long_description=long_description,
35-
py_modules=['nbstripout'],
35+
packages=find_packages(),
36+
provides=['nbstripout'],
3637
entry_points={
3738
'console_scripts': [
38-
'nbstripout = nbstripout:main'
39+
'nbstripout = nbstripout.nbstripout:main'
3940
],
4041
},
4142

tests/test_functions.py

-7
This file was deleted.

tests/test_utils.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from nbstripout.utils import pop_recursive
2+
3+
4+
def test_pop_recursive():
5+
d = {'a': {'b': 1, 'c': 2}}
6+
assert pop_recursive(d, 'a.c') == 2
7+
assert d == {'a': {'b': 1}}

0 commit comments

Comments
 (0)