Browse Source

Update TwoWayOrderedDict to latest version

doc-issue-template
MrS0m30n3 9 years ago
parent
commit
5ab0035c09
1 changed files with 120 additions and 142 deletions
  1. 262
      youtube_dl_gui/utils.py

262
youtube_dl_gui/utils.py

@ -3,7 +3,7 @@
"""Youtubedlg module that contains util functions.
Attributes:
RANDOM_OBJECT (object): Object that it's used as a default parameter.
_RANDOM_OBJECT (object): Object that it's used as a default parameter.
YOUTUBEDL_BIN (string): Youtube-dl binary filename.
@ -15,7 +15,7 @@ import sys
import subprocess
RANDOM_OBJECT = object()
_RANDOM_OBJECT = object()
YOUTUBEDL_BIN = 'youtube-dl'
@ -163,7 +163,7 @@ def get_icon_file():
return None
class TwoWayOrderedDict(object):
class TwoWayOrderedDict(dict):
"""Custom data structure which implements a two way ordrered dictionary.
@ -171,7 +171,7 @@ class TwoWayOrderedDict(object):
key:value relationship but you can also get the value:key relationship.
It also remembers the order in which the items were inserted and supports
almost all the features of the build-in dict.
Note:
Ways to create a new dictionary.
@ -188,200 +188,178 @@ class TwoWayOrderedDict(object):
>>> d[1]
'a'
>>> print d
{'a': 1, 'b': 2}
TwoWayOrderedDict([('a', 1), ('b', 2)])
"""
def __init__(self, *args, **kwargs):
self._items = list()
self._load_into_dict(args, kwargs)
_PREV = 0
_KEY = 1
_NEXT = 2
def __getitem__(self, key):
try:
item = self._find_item(key)
return self._get_value(key, item)
except KeyError as error:
raise error
def __init__(self, *args, **kwargs):
self._items = item = []
self._items += [item, None, item] # Double linked list [prev, key, next]
self._items_map = {} # Map link list items into keys to speed up lookup
self._load(args, kwargs)
def __setitem__(self, key, value):
index = 0
while index < len(self._items):
item = self._items[index]
if key in self:
# If self[key] == key for example {'b': 'b'} and we
# do d['b'] = 2 then we dont want to remove the 'b'
# from our linked list because we will lose the order
if self[key] in self._items_map and key != self[key]:
self._remove_mapped_key(self[key])
dict.__delitem__(self, self[key])
if value in self:
# If value == key we dont have to remove the
# value from the items_map because the value is
# the key and we want to keep the key in our
# linked list in order to keep the order.
if value in self._items_map and key != value:
self._remove_mapped_key(value)
if self[value] in self._items_map:
self._remove_mapped_key(self[value])
# Check if self[value] is in the dict
# for cases like {'a': 'a'} where we
# have only one copy instead of {'a': 1, 1: 'a'}
if self[value] in self:
dict.__delitem__(self, self[value])
if key not in self._items_map:
last = self._items[self._PREV] # self._items prev always points to the last item
last[self._NEXT] = self._items[self._PREV] = self._items_map[key] = [last, key, self._items]
dict.__setitem__(self, key, value)
dict.__setitem__(self, value, key)
if (key == item[0] or key == item[1] or
value == item[0] or value == item[1]):
self._items.remove(item)
else:
index += 1
def __delitem__(self, key):
if self[key] in self._items_map:
self._remove_mapped_key(self[key])
self._items.append((key, value))
if key in self._items_map:
self._remove_mapped_key(key)
def __delitem__(self, key):
try:
item = self._find_item(key)
dict.__delitem__(self, self[key])
self._items.remove(item)
except KeyError as error:
raise error
# Check if key is in the dict
# for cases like {'a': 'a'} where we
# have only one copy instead of {'a': 1, 1: 'a'}
if key in self:
dict.__delitem__(self, key)
def __len__(self):
return len(self._items)
return len(self._items_map)
def __iter__(self):
for item in self._items:
yield item[0]
def __contains__(self, item):
"""Return True if the item matches either a
dictionary key or value else False. """
try:
self._find_item(item)
except KeyError:
return False
curr = self._items[self._NEXT]
while curr is not self._items:
yield curr[self._KEY]
curr = curr[self._NEXT]
return True
def __reversed__(self):
curr = self._items[self._PREV]
while curr is not self._items:
yield curr[self._KEY]
curr = curr[self._PREV]
def __repr__(self):
return str(self._items)
def __str__(self):
return str(dict(self._items))
def _get_value(self, key, item):
"""Return the key:value or value:key relationship
for the given item. """
if key == item[0]:
return item[1]
if key == item[1]:
return item[0]
def _find_item(self, key):
"""Search for the item which contains the given key.
This method will compare the key both with the key and the value
of the item until it finds a match else it will raise a KeyError
exception.
Returns:
item (tuple): Tuple which contains the (key, value).
Raises:
KeyError
"""
for item in self._items:
if key == item[0] or key == item[1]:
return item
return '%s(%r)' % (self.__class__.__name__, self.items())
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.items() == other.items()
return False
raise KeyError(key)
def __ne__(self, other):
return not self == other
def _load_into_dict(self, args, kwargs):
"""Load new items into the dictionary. This method handles the
items insertion for the __init__ and update methods. """
def _remove_mapped_key(self, key):
"""Remove the given key both from the linked list
and the map dictionary. """
prev, __, next = self._items_map.pop(key)
prev[self._NEXT] = next
next[self._PREV] = prev
def _load(self, args, kwargs):
"""Load items into our dictionary. """
for item in args:
if type(item) == dict:
item = item.items()
item = item.iteritems()
for key, value in item:
self.__setitem__(key, value)
self[key] = value
for key, value in kwargs.items():
self.__setitem__(key, value)
self[key] = value
def items(self):
"""Return the item list instead of returning the dict view. """
return self._items
return [(key, self[key]) for key in self]
def values(self):
"""Return a list with all the values of the dictionary instead of
returning the dict view for the values. """
return [item[1] for item in self._items]
return [self[key] for key in self]
def keys(self):
"""Return a list with all the keys of the dictionary instead of
returning the dict view for the keys. """
return [item[0] for item in self._items]
def get(self, key, default=None):
"""Return the value for key or the key for value if key
is in the dictionary else default.
Note:
This method does NOT raise a KeyError.
"""
try:
return self.__getitem__(key)
except KeyError:
return default
return list(self)
def pop(self, key, default=RANDOM_OBJECT):
"""If key is in the dictionary remove it and return its value
else return default. If default is not given and key is not in
the dictionary a KeyError is raised. """
def pop(self, key, default=_RANDOM_OBJECT):
try:
item = self._find_item(key)
value = self._get_value(key, item)
value = self[key]
self._items.remove(item)
del self[key]
except KeyError as error:
if default == RANDOM_OBJECT:
if default == _RANDOM_OBJECT:
raise error
value = default
return value
def popitem(self):
def popitem(self, last=True):
"""Remove and return a (key, value) pair from the dictionary.
If the dictionary is empty calling popitem() raises a KeyError.
Args:
last (bool): When False popitem() will remove the first item
from the list.
Note:
popitem() is useful to destructively iterate over a dictionary.
Raises:
KeyError
"""
if len(self._items) == 0:
if not self:
raise KeyError('popitem(): dictionary is empty')
return self._items.pop()
if last:
__, key, __ = self._items[self._PREV]
else:
__, key, __ = self._items[self._NEXT]
value = self.pop(key)
return key, value
def update(self, *args, **kwargs):
self._load(args, kwargs)
def setdefault(self, key, default=None):
"""If key is in the dictionary return its value else
insert a new key with a value of default and return default. """
try:
return self.__getitem__(key)
return self[key]
except KeyError:
self.__setitem__(key, default)
self[key] = default
return default
def update(self, *args, **kwargs):
"""Update the dictionary with the (key, value) pairs
overwriting existing keys.
Example:
>>d = TwoWayOrderedDict(a=1, b=2)
>>print d
{'a': 1, 'b': 2}
>>d.update({'a': 0, 'b': 1, 'c': 2})
{'a': 0, 'b': 1, 'c': 2}
>>d.update(d=3)
{'a': 0, 'b': 1, 'c': 2, 'd': 3}
"""
self._load_into_dict(args, kwargs)
def copy(self):
"""Return a copy of our custom dictionary. """
return TwoWayOrderedDict(self._items)
return self.__class__(self.items())
def clear(self):
"""Remove all items from the dictionary. """
del self._items[:]
self._items = item = []
self._items += [item, None, item]
self._items_map = {}
dict.clear(self)
Loading…
Cancel
Save