Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
stefankoegl committed Apr 2, 2018
1 parent f301608 commit ed1aea7
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 113 deletions.
258 changes: 147 additions & 111 deletions jsonpatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -627,135 +627,160 @@ class DiffBuilder(object):
def __init__(self, src, dst):
self.src = src
self.dst = dst
self.index_storage = [{}, {}]
self.index_storage2 = [[], []]
self.__root = root = []
root[:] = [root, root, None]

def store_index(self, value, index, st):
try:
storage = self.index_storage[st]
stored = storage.get(value)
if stored is None:
storage[value] = [index]
else:
storage[value].append(index)

except TypeError:
self.index_storage2[st].append((value, index))

def take_index(self, value, st):
try:
stored = self.index_storage[st].get(value)
if stored:
return stored.pop()
self.ops = []
self.index_changes = {}

except TypeError:
storage = self.index_storage2[st]
for i in range(len(storage)-1, -1, -1):
if storage[i][0] == value:
return storage.pop(i)[1]
# self.index_storage = [{}, {}]
# self.index_storage2 = [[], []]
#
# self.__root = root = []
# root[:] = [root, root, None]

# def store_index(self, value, index, st):
# try:
# storage = self.index_storage[st]
# stored = storage.get(value)
# if stored is None:
# storage[value] = [index]
# else:
# storage[value].append(index)
#
# except TypeError:
# self.index_storage2[st].append((value, index))
#
# def take_index(self, value, st):
# try:
# stored = self.index_storage[st].get(value)
# if stored:
# return stored.pop()
#
# except TypeError:
# storage = self.index_storage2[st]
# for i in range(len(storage)-1, -1, -1):
# if storage[i][0] == value:
# return storage.pop(i)[1]

def insert(self, op):
root = self.__root
last = root[0]
last[1] = root[0] = [last, root, op]
return root[0]

def remove(self, index):
link_prev, link_next, _ = index
link_prev[1] = link_next
link_next[0] = link_prev
index[:] = []

def iter_from(self, start):
root = self.__root
curr = start[1]
while curr is not root:
yield curr[2]
curr = curr[1]

def __iter__(self):
root = self.__root
curr = root[1]
while curr is not root:
yield curr[2]
curr = curr[1]
self.ops.append(op)
# root = self.__root
# last = root[0]
# last[1] = root[0] = [last, root, op]
# return root[0]
#
# def remove(self, index):
# link_prev, link_next, _ = index
# link_prev[1] = link_next
# link_next[0] = link_prev
# index[:] = []
#
# def iter_from(self, start):
# root = self.__root
# curr = start[1]
# while curr is not root:
# yield curr[2]
# curr = curr[1]
#
# def __iter__(self):
# root = self.__root
# curr = root[1]
# while curr is not root:
# yield curr[2]
# curr = curr[1]

def execute(self):
self._compare_values('', None, self.src, self.dst)

root = self.__root
curr = root[1]
while curr is not root:
if curr[1] is not root:
op_first, op_second = curr[2], curr[1][2]
if op_first.location == op_second.location and \
type(op_first) == RemoveOperation and \
type(op_second) == AddOperation:
yield ReplaceOperation({
'op': 'replace',
'path': op_second.location,
'value': op_second.operation['value'],
}).operation
curr = curr[1][1]
continue

yield curr[2].operation
curr = curr[1]
return list(self.ops)

# root = self.__root
# curr = root[1]
# while curr is not root:
# if curr[1] is not root:
# op_first, op_second = curr[2], curr[1][2]
# if op_first.location == op_second.location and \
# type(op_first) == RemoveOperation and \
# type(op_second) == AddOperation:
# yield ReplaceOperation({
# 'op': 'replace',
# 'path': op_second.location,
# 'value': op_second.operation['value'],
# }).operation
# curr = curr[1][1]
# continue
#
# yield curr[2].operation
# curr = curr[1]

def _item_added(self, path, key, item):
index = self.take_index(item, _ST_REMOVE)
if index is not None:
op = index[2]
if type(op.key) == int:
for v in self.iter_from(index):
op.key = v._on_undo_remove(op.path, op.key)

self.remove(index)
if op.location != _path_join(path, key):
new_op = MoveOperation({
'op': 'move',
'from': op.location,
'path': _path_join(path, key),
})
self.insert(new_op)
else:
new_op = AddOperation({
'op': 'add',
'path': _path_join(path, key),
'value': item,
})
new_index = self.insert(new_op)
self.store_index(item, new_index, _ST_ADD)
key = self.get_index_change(path, key)

new_op = AddOperation({
'op': 'add',
'path': _path_join(path, key),
'value': item,
})
self.insert(new_op)

self.add_index_change(path, key, +1)

# index = self.take_index(item, _ST_REMOVE)
# if index is not None:
# op = index[2]
# if type(op.key) == int:
# for v in self.iter_from(index):
# op.key = v._on_undo_remove(op.path, op.key)
#
# self.remove(index)
# if op.location != _path_join(path, key):
# new_op = MoveOperation({
# 'op': 'move',
# 'from': op.location,
# 'path': _path_join(path, key),
# })
# self.insert(new_op)
# else:
# new_op = AddOperation({
# 'op': 'add',
# 'path': _path_join(path, key),
# 'value': item,
# })
# new_index = self.insert(new_op)
# self.store_index(item, new_index, _ST_ADD)

def _item_removed(self, path, key, item):
key = self.get_index_change(path, key)

new_op = RemoveOperation({
'op': 'remove',
'path': _path_join(path, key),
})
index = self.take_index(item, _ST_ADD)
new_index = self.insert(new_op)
if index is not None:
op = index[2]
if type(op.key) == int:
for v in self.iter_from(index):
op.key = v._on_undo_add(op.path, op.key)

self.remove(index)
if new_op.location != op.location:
new_op = MoveOperation({
'op': 'move',
'from': new_op.location,
'path': op.location,
})
new_index[2] = new_op
self.insert(new_op)

else:
self.remove(new_index)
self.add_index_change(path, key, -1)

else:
self.store_index(item, new_index, _ST_REMOVE)
# index = self.take_index(item, _ST_ADD)
# new_index = self.insert(new_op)
# if index is not None:
# op = index[2]
# if type(op.key) == int:
# for v in self.iter_from(index):
# op.key = v._on_undo_add(op.path, op.key)
#
# self.remove(index)
# if new_op.location != op.location:
# new_op = MoveOperation({
# 'op': 'move',
# 'from': new_op.location,
# 'path': op.location,
# })
# new_index[2] = new_op
#
# else:
# self.remove(new_index)
#
# else:
# self.store_index(item, new_index, _ST_REMOVE)

def _item_replaced(self, path, key, item):
self.insert(ReplaceOperation({
Expand Down Expand Up @@ -822,6 +847,17 @@ def _compare_values(self, path, key, src, dst):
else:
self._item_replaced(path, key, dst)

def add_index_change(self, path, key, change):
path_changes = self.index_changes.get(path, {})
key_change = path_changes.get(key, 0)
key_change = key_change + change
path_changes[key] = key_change

def get_index_change(self, path, key):
path_changes = self.index_changes.get(path, {})
keys = patch...



def _path_join(path, key):
if key is None:
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
except ImportError:
print('warning: pypandoc module not found, could not convert '
'Markdown to RST')
read_md = lambda f: open(f, 'r').read()
read_md = lambda f: io.open(f, encoding='utf-8').read()

CLASSIFIERS = [
'Development Status :: 5 - Production/Stable',
Expand Down
4 changes: 3 additions & 1 deletion tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,9 @@ def test_roundtrip(self, src, dst):
patch = jsonpatch.JsonPatch.from_diff(src, dst, False)
hypothesis.note('Patch: %s' % (patch,))
res = patch.apply(src)
self.assertEqual(res, dst)
message = '{src} + {patch} resulted in {res}; {dst} was expected'.format(
src=repr(src), patch=repr(patch), res=repr(res), dst=repr(dst))
self.assertEqual(res, dst, message)


if __name__ == '__main__':
Expand Down

0 comments on commit ed1aea7

Please sign in to comment.