from collections import OrderedDict
[docs]class Collection(OrderedDict):
current = None
current_key_id = 0
targets = []
[docs] def get_current_key(self):
"""
Get the current key that maps to the current object
"""
return self.get_keys()[self.current_key_id]
[docs] def set_current(self, target):
"""
Set the current data
:param key_or_id: A valid key or an int or the data
object itself
"""
keys = self.get_keys()
if target in self:
key = target
elif isinstance(target, int):
key_id = target
try:
key = keys[key_id]
except Exception:
return
else:
for key in self:
if self[key] == target:
break
key_id = 0
for other_key in keys:
if other_key == key:
break
key_id += 1
# This is for when you need to know where is the key in the array
self.current_key_id = key_id
self.current = self.get(key)
[docs] def next(self, loop=False):
"""
Set the next data as current one
:param loop: Whether looping is enabled,
which means that if next value is out of range,
we start back at 0
"""
keys = self.get_keys()
new_id = self.current_id + 1
if new_id > len(keys) - 1:
new_id = 0 if loop else len(keys) - 1
self.set_current(new_id)
return new_id
[docs] def previous(self, loop=False):
"""
Set the previous data as current one
:param loop: Whether looping is enabled,
which means that if previous value is out of range,
we go to -1 in a backward loop
"""
keys = self.get_keys()
new_id = self.current_id - 1
if new_id < 0:
new_id = len(keys) - 1 if loop else 0
self.set_current(new_id)
return new_id
[docs] def store(self, data, data_id=None, replace_existing=True, set_current=False):
"""
Store a data
:param data: data instance
:param data_id: data id, a unique string if possible.
If it's not a unique string, it will be appended a
number so that it's unique.
:param replace_existing: Whether any existing data with the same id is replaced or not
:param set_current: Whether the newly stored data is set as the current one
:return: The new data_id or None
"""
if data_id is None or (data_id in self and not replace_existing):
data_id = self.get_new_name(data)
if data_id in self and not replace_existing:
return
self[data_id] = data
if set_current or len(self) == 1:
self.set_current(data_id)
return data_id
[docs] def get_or_create(self, data_id, data_class=None):
"""
Get a data from a dictionary of data or create it if none found.
This method works only with datas that have a name (str) property.
:param data_id: Either a data name or its id
:param data_class: The class of the data
:return: A data of type data_class
"""
name = data_id
if isinstance(data_id, int):
name = self.get_keys()[data_id]
data = self.get(name)
if data is None and data_class is not None:
if isinstance(data_id, str):
data = data_class(name=data_id)
else:
data = data_class()
data_id = self.get_new_name(data)
self[data_id] = data
return data
[docs] def get_keys(self):
"""
Get all data ids
"""
return list(self.keys())
[docs] def find_keys(self, id_or_subid):
"""
Get all ids/keys that have the given param as a substring
"""
keys = self.get_keys()
found_ones = []
for key in keys:
if id_or_subid in key: #key could be an array or any iterable too
found_ones.append(key)
return found_ones
[docs] def get_new_name(self, obj):
"""
Get a new name derived from an object's class name
:return: String
"""
return f'{obj.__class__.__name__}{len(self)}'
[docs] def get_name(self, *args):
"""
Get given arguments separated by underscores as a single string
:return: String
"""
return '_'.join(args)