Skip to content

Commit

Permalink
Added placeholder for cli tests. Update docs a bit. Various minor edi…
Browse files Browse the repository at this point in the history
…ts and comments.
  • Loading branch information
Martin Sandve Alnæs committed Dec 21, 2015
1 parent 1ef659c commit e0ad993
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 36 deletions.
31 changes: 6 additions & 25 deletions docs/source/diffing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,27 +52,13 @@ A diff of two dicts is a list of diff entries:

A dict diff entry is a list of action and argument (except for deletion):

* ["-", key]: delete value at key
* ["+", key, newvalue]: insert newvalue at key
* ["-", key]: delete existing value at key
* ["+", key, value]: insert new value at key
* [":", key, value]: replace value at key with newvalue
* ["!", key, diff]: patch value at key with diff
* [":", key, newvalue]: replace value at key with newvalue


Diff format for dicts (alternative)
-----------------------------------

A diff of two dicts is itself a dict mapping string keys to diff entries:

key = string
entry = [action] | [action, argument]
diff = {key0:entry0, key1: entry1, ...}

A dict diff entry is a list of action and argument (except for deletion):

* ["-"]: delete value at key
* ["+", newvalue]: insert newvalue at key
* ["!", diff]: patch value at key with diff
* [":", newvalue]: replace value at key with newvalue
Insert is an error if the key already exists.
Delete, replace and patch are errors if the key does not already exist.


Diff format for sequences (list and string)
Expand All @@ -91,10 +77,5 @@ A sequence diff entry is a list of action, index and argument (except for deleti
* ["--", index, n]: delete n entries starting at index
* ["++", index, newvalues]: insert sequence newvalues before index
* ["!", index, diff]: patch value at index with diff
* [":", index, newvalue]: replace value at index with newvalue

Possible simplifications:

* Remove the ":" action.
* Remove single-item "-", "+" and rename "--" and "++" to single-letter.
* OR remove "--" and "++" and stick with just single-item versions.
Possible simplification: Remove single-item insert/delete for sequences.
5 changes: 3 additions & 2 deletions nbdime/dformat.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

from .log import error, NBDiffFormatError


# Valid values for the action field in diff entries
PATCH = "!"
INSERT = "+"
Expand Down Expand Up @@ -202,12 +203,12 @@ def to_json_patch_format(d, path=""):
jp.append({"op": "add", "path": p, "value": e[2]})
elif op == REPLACE:
jp.append({"op": "replace", "path": p, "value": e[2]})
elif op == REMOVE:
elif op == DELETE:
jp.append({"op": "remove", "path": p})
elif op == SEQINSERT:
for value in e[2]: # FIXME: Reverse this or not? Read RFC carefully and/or test with some conforming tool.
jp.append({"op": "add", "path": p, "value": e[2]})
elif op == SEQREMOVE:
elif op == SEQDELETE:
for i in range(e[1], e[1]+e[2]):
jp.append({"op": "remove", "path": "/".join((path, str(i)))})
elif op == PATCH:
Expand Down
3 changes: 1 addition & 2 deletions nbdime/diffing/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def diff_lists(a, b, compare=operator.__eq__, shallow_diff=None):
return pdi


def diff_dicts(a, b, compare=operator.__eq__):
def diff_dicts(a, b, compare):
"""Compute diff of two dicts with configurable behaviour.
Keys in both a and b will be handled based on
Expand Down Expand Up @@ -119,7 +119,6 @@ def diff_dicts(a, b, compare=operator.__eq__):

def diff(a, b, compare=operator.__eq__):
"Compute the diff of two json-like objects, list or dict or string."

# TODO: Providing separate comparison predicate for
# different dict paths will allow more customization

Expand Down
10 changes: 6 additions & 4 deletions nbdime/diffing/lcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

from six.moves import xrange as range

from ..dformat import SEQDELETE, SEQINSERT

def diff_from_lcs(A, B, A_indices, B_indices):
"""Compute the diff of A and B, given indices of their lcs."""
diff = []
Expand All @@ -20,13 +22,13 @@ def diff_from_lcs(A, B, A_indices, B_indices):
i = A_indices[r]
j = B_indices[r]
if i > x:
diff.append(["--", x, i-x])
diff.append([SEQDELETE, x, i-x])
if j > y:
diff.append(["++", x, B[y:j]])
diff.append([SEQINSERT, x, B[y:j]])
x = i + 1
y = j + 1
if x < N:
diff.append(["--", x, N-x])
diff.append([SEQDELETE, x, N-x])
if y < M:
diff.append(["++", x, B[y:M]])
diff.append([SEQINSERT, x, B[y:M]])
return diff
7 changes: 4 additions & 3 deletions nbdime/diffing/notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

import operator

from ..dformat import PATCH, INSERT, DELETE, REPLACE, SEQINSERT, SEQDELETE
from ..dformat import PATCH
#, INSERT, DELETE, REPLACE, SEQINSERT, SEQDELETE
from ..dformat import decompress_diff

from .comparing import strings_are_similar
Expand Down Expand Up @@ -60,10 +61,10 @@ def diff_notebooks(nba, nbb):
acells = nba.pop("cells")
bcells = nbb.pop("cells")

# Diff the rest
# Diff the rest of the notebook using generic tools
nbdiff = diff(nba, nbb)

# Then add specialized cells diff
# Then apply a specialized approach to diffing cells
cdiff = diff_cells(acells, bcells)
if cdiff:
nbdiff.append([PATCH, "cells", cdiff])
Expand Down
2 changes: 2 additions & 0 deletions nbdime/diffing/seq_difflib.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

__all__ = ["diff_sequence_difflib"]


def opcodes_to_diff(a, b, opcodes):
"Convert difflib opcodes to nbdime diff format."
d = []
Expand All @@ -31,6 +32,7 @@ def opcodes_to_diff(a, b, opcodes):
raise RuntimeError("Unknown action {}".format(action))
return d


def diff_sequence_difflib(a, b):
"""Compute the diff of two sequences.
Expand Down
32 changes: 32 additions & 0 deletions nbdime/tests/test_cli_apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

from __future__ import unicode_literals

import pytest

from nbdime.nbdiffapp import main_diff
from nbdime.nbpatchapp import main_patch
from nbdime.nbmergeapp import main_merge


@pytest.mark.xfail(reason="need to add actual test files")
def test_nbdiff_app():
afn = "a.ipynb"
bfn = "b.ipynb"
dfn = "d.json"
assert 0 == main_diff(afn, bfn, dfn)


@pytest.mark.xfail(reason="need to add actual test files")
def test_nbpatch_app():
afn = "a.ipynb"
dfn = "d.json"
assert 0 == main_patch(afn, dfn)


@pytest.mark.xfail(reason="need to add actual test files")
def test_nbmerge_app():
bfn = "b.ipynb"
lfn = "l.ipynb"
rfn = "r.ipynb"
mfn = "m.ipynb"
assert 0 == main_merge(bfn, lfn, rfn, mfn)
2 changes: 2 additions & 0 deletions nbdime/tests/test_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def test_patch_str():
assert patch("abcd", [[SEQDELETE, 1, 2]]) == "ad"
assert patch("abcd", [[SEQDELETE, 2, 2]]) == "ab"


def test_patch_list():
# Test +, single item insertion
assert patch([], [[INSERT, 0, 3]]) == [3]
Expand Down Expand Up @@ -71,6 +72,7 @@ def test_patch_list():
assert patch([5, 6, 7, 8], [[SEQDELETE, 1, 2]]) == [5, 8]
assert patch([5, 6, 7, 8], [[SEQDELETE, 2, 2]]) == [5, 6]


def test_patch_dict():
# Test +, single item insertion
assert patch({}, [[INSERT, "d", 4]]) == {"d": 4}
Expand Down

0 comments on commit e0ad993

Please sign in to comment.