Skip to content

Commit aeb15c9

Browse files
committed
refactor
1 parent 4db55ff commit aeb15c9

File tree

3 files changed

+52
-42
lines changed

3 files changed

+52
-42
lines changed

nbdev/_modidx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
'nbdev.config.update_version': ('api/config.html#update_version', 'nbdev/config.py'),
5151
'nbdev.config.write_cells': ('api/config.html#write_cells', 'nbdev/config.py')},
5252
'nbdev.diff': { 'nbdev.diff._cell_changes': ('api/diff.html#_cell_changes', 'nbdev/diff.py'),
53+
'nbdev.diff._nb_srcdict': ('api/diff.html#_nb_srcdict', 'nbdev/diff.py'),
5354
'nbdev.diff.cell_diffs': ('api/diff.html#cell_diffs', 'nbdev/diff.py'),
5455
'nbdev.diff.changed_cells': ('api/diff.html#changed_cells', 'nbdev/diff.py'),
5556
'nbdev.diff.nbs_pair': ('api/diff.html#nbs_pair', 'nbdev/diff.py'),

nbdev/diff.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,33 @@
1616
# %% ../nbs/api/19_diff.ipynb
1717
def read_nb_from_git(
1818
g:Git, # The git object
19-
ref, # The git ref to read from (e.g. HEAD)
20-
path # The path to the notebook in git
19+
path, # The path to the notebook (absolute or relative to git root)
20+
ref=None # The git ref to read from (e.g. HEAD); None for working dir
2121
)->AttrDict: # The notebook
22-
"Read notebook from git ref (e.g. HEAD) at path"
22+
"Read notebook from git ref (e.g. HEAD) at path, or working dir if ref is None"
23+
path = Path(path)
24+
if path.is_absolute(): path = path.relative_to(g.top())
25+
if ref is None: return read_nb(g.top()/path)
2326
raw = g.show(f'{ref}:{path}', split=False)
2427
return dict2nb(json.loads(raw))
2528

29+
# %% ../nbs/api/19_diff.ipynb
30+
def _nb_srcdict(g:Git, nb_path, ref=None, f=noop):
31+
"Dict of id->source"
32+
nb = read_nb_from_git(g, nb_path, ref)
33+
return {c['id']: f(c) for c in nb.cells}
34+
2635
# %% ../nbs/api/19_diff.ipynb
2736
def nbs_pair(
2837
nb_path, # Path to the notebook
2938
ref_a='HEAD', # First git ref (None for working dir)
30-
ref_b=None # Second git ref (None for working dir)
39+
ref_b=None, # Second git ref (None for working dir)
40+
f=noop # Function to call on contents
3141
): # Tuple of two notebooks
3242
"NBs at two refs; None means working dir. By default provides HEAD and working dir"
3343
nb_path = Path(nb_path).resolve()
3444
g = Git(nb_path.parent)
35-
rel = nb_path.relative_to(g.top())
36-
nb_a = read_nb_from_git(g, ref_a, str(rel)) if ref_a else read_nb(nb_path)
37-
nb_b = read_nb_from_git(g, ref_b, str(rel)) if ref_b else read_nb(nb_path)
38-
return nb_a, nb_b
45+
return _nb_srcdict(g, nb_path, ref_a, f), _nb_srcdict(g, nb_path, ref_b, f)
3946

4047
# %% ../nbs/api/19_diff.ipynb
4148
def _cell_changes(
@@ -50,14 +57,12 @@ def _cell_changes(
5057
outputs=False # Consider cell outputs when comparing
5158
): # Dict of results
5259
"Apply fn(cell_id, old_content, new_content) to changed cells between two refs"
53-
nb_a, nb_b = nbs_pair(nb_path, ref_a, ref_b)
5460
def cell_content(c):
5561
res = c.get('source', '')
5662
if metadata: res += '\n# metadata: ' + json.dumps(c.get('metadata', {}), sort_keys=True)
5763
if outputs: res += '\n# outputs: ' + json.dumps(c.get('outputs', []), sort_keys=True)
5864
return res
59-
old = {c['id']: cell_content(c) for c in nb_a.cells}
60-
new = {c['id']: cell_content(c) for c in nb_b.cells}
65+
old,new = nbs_pair(nb_path, ref_a, ref_b, f=cell_content)
6166
res = {}
6267
if adds: res |= {cid: fn(cid, '', new[cid]) for cid in new if cid not in old}
6368
if changes: res |= {cid: fn(cid, old[cid], new[cid]) for cid in new if cid in old and new[cid] != old[cid]}

nbs/api/19_diff.ipynb

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -79,25 +79,28 @@
7979
{
8080
"cell_type": "code",
8181
"execution_count": null,
82-
"id": "f53b610f",
82+
"id": "a8981115",
8383
"metadata": {},
8484
"outputs": [],
8585
"source": [
8686
"#| export\n",
8787
"def read_nb_from_git(\n",
8888
" g:Git, # The git object\n",
89-
" ref, # The git ref to read from (e.g. HEAD)\n",
90-
" path # The path to the notebook in git\n",
89+
" path, # The path to the notebook (absolute or relative to git root)\n",
90+
" ref=None # The git ref to read from (e.g. HEAD); None for working dir\n",
9191
")->AttrDict: # The notebook\n",
92-
" \"Read notebook from git ref (e.g. HEAD) at path\"\n",
92+
" \"Read notebook from git ref (e.g. HEAD) at path, or working dir if ref is None\"\n",
93+
" path = Path(path)\n",
94+
" if path.is_absolute(): path = path.relative_to(g.top())\n",
95+
" if ref is None: return read_nb(g.top()/path)\n",
9396
" raw = g.show(f'{ref}:{path}', split=False)\n",
9497
" return dict2nb(json.loads(raw))"
9598
]
9699
},
97100
{
98101
"cell_type": "code",
99102
"execution_count": null,
100-
"id": "89ebfaa2",
103+
"id": "f0fdf8e5",
101104
"metadata": {},
102105
"outputs": [
103106
{
@@ -125,64 +128,66 @@
125128
}
126129
],
127130
"source": [
128-
"read_nb_from_git(g, 'HEAD', 'test.ipynb').cells"
131+
"read_nb_from_git(g, 'test.ipynb', 'HEAD').cells"
129132
]
130133
},
131134
{
132135
"cell_type": "code",
133136
"execution_count": null,
134-
"id": "e7032b25",
137+
"id": "3ac25702",
135138
"metadata": {},
136139
"outputs": [],
137140
"source": [
138141
"#| export\n",
139-
"def nbs_pair(\n",
140-
" nb_path, # Path to the notebook\n",
141-
" ref_a='HEAD', # First git ref (None for working dir)\n",
142-
" ref_b=None # Second git ref (None for working dir)\n",
143-
"): # Tuple of two notebooks\n",
144-
" \"NBs at two refs; None means working dir. By default provides HEAD and working dir\"\n",
145-
" nb_path = Path(nb_path).resolve()\n",
146-
" g = Git(nb_path.parent)\n",
147-
" rel = nb_path.relative_to(g.top())\n",
148-
" nb_a = read_nb_from_git(g, ref_a, str(rel)) if ref_a else read_nb(nb_path)\n",
149-
" nb_b = read_nb_from_git(g, ref_b, str(rel)) if ref_b else read_nb(nb_path)\n",
150-
" return nb_a, nb_b"
142+
"def _nb_srcdict(g:Git, nb_path, ref=None, f=noop):\n",
143+
" \"Dict of id->source\"\n",
144+
" nb = read_nb_from_git(g, nb_path, ref)\n",
145+
" return {c['id']: f(c) for c in nb.cells}"
151146
]
152147
},
153148
{
154149
"cell_type": "code",
155150
"execution_count": null,
156-
"id": "154c92ed",
151+
"id": "27ff9a7b",
157152
"metadata": {},
158153
"outputs": [],
159154
"source": [
160-
"a,b = nbs_pair(nb_path)"
155+
"#| export\n",
156+
"def nbs_pair(\n",
157+
" nb_path, # Path to the notebook\n",
158+
" ref_a='HEAD', # First git ref (None for working dir)\n",
159+
" ref_b=None, # Second git ref (None for working dir)\n",
160+
" f=noop # Function to call on contents\n",
161+
"): # Tuple of two notebooks\n",
162+
" \"NBs at two refs; None means working dir. By default provides HEAD and working dir\"\n",
163+
" nb_path = Path(nb_path).resolve()\n",
164+
" g = Git(nb_path.parent)\n",
165+
" return _nb_srcdict(g, nb_path, ref_a, f), _nb_srcdict(g, nb_path, ref_b, f)"
161166
]
162167
},
163168
{
164169
"cell_type": "code",
165170
"execution_count": null,
166-
"id": "dddea7bc",
171+
"id": "154c92ed",
167172
"metadata": {},
168173
"outputs": [
169174
{
170175
"data": {
171176
"text/plain": [
172-
"({'cell_type': 'code',\n",
177+
"{'390c8c7d': {'cell_type': 'code',\n",
173178
" 'execution_count': 0,\n",
174179
" 'id': '390c8c7d',\n",
175180
" 'metadata': {},\n",
176181
" 'outputs': [],\n",
177182
" 'source': 'x=1',\n",
178183
" 'idx_': 0},\n",
179-
" {'cell_type': 'code',\n",
184+
" '7247342c': {'cell_type': 'code',\n",
180185
" 'execution_count': 0,\n",
181-
" 'id': '390c8c7d',\n",
186+
" 'id': '7247342c',\n",
182187
" 'metadata': {},\n",
183188
" 'outputs': [],\n",
184-
" 'source': 'x = 100',\n",
185-
" 'idx_': 0})"
189+
" 'source': 'y=2',\n",
190+
" 'idx_': 1}}"
186191
]
187192
},
188193
"execution_count": null,
@@ -191,7 +196,8 @@
191196
}
192197
],
193198
"source": [
194-
"a.cells[0], b.cells[0]"
199+
"a,b = nbs_pair(nb_path)\n",
200+
"a"
195201
]
196202
},
197203
{
@@ -214,14 +220,12 @@
214220
" outputs=False # Consider cell outputs when comparing\n",
215221
"): # Dict of results\n",
216222
" \"Apply fn(cell_id, old_content, new_content) to changed cells between two refs\"\n",
217-
" nb_a, nb_b = nbs_pair(nb_path, ref_a, ref_b)\n",
218223
" def cell_content(c):\n",
219224
" res = c.get('source', '')\n",
220225
" if metadata: res += '\\n# metadata: ' + json.dumps(c.get('metadata', {}), sort_keys=True)\n",
221226
" if outputs: res += '\\n# outputs: ' + json.dumps(c.get('outputs', []), sort_keys=True)\n",
222227
" return res\n",
223-
" old = {c['id']: cell_content(c) for c in nb_a.cells}\n",
224-
" new = {c['id']: cell_content(c) for c in nb_b.cells}\n",
228+
" old,new = nbs_pair(nb_path, ref_a, ref_b, f=cell_content)\n",
225229
" res = {}\n",
226230
" if adds: res |= {cid: fn(cid, '', new[cid]) for cid in new if cid not in old}\n",
227231
" if changes: res |= {cid: fn(cid, old[cid], new[cid]) for cid in new if cid in old and new[cid] != old[cid]}\n",

0 commit comments

Comments
 (0)