elineve's picture
Upload 301 files
07423df
raw
history blame
3.38 kB
from typing import Iterable, List, Optional
class Order:
"""
A list-like structure to specify the order of items in a dictionary.
The main characteristics are:
- Append and insert only. Cannot remove elements. This is not strictly required
by the use-case but probably good practice.
- Elements must be unique. Inserting an element which is already in the list
will throw an error.
Primarily useful for specifying the order in which UI elements
should be shown in Wave.
"""
def __init__(self, keys: Optional[List[str]] = None):
if keys is not None:
self._list = list(keys)
else:
self._list = list()
def _unique_guard(self, *keys: str):
for key in keys:
if key in self._list:
raise ValueError(f"`{key}` is already in the list!")
def append(self, key: str):
"""
Append a key at the end of the list:
Args:
key: String to append.
Raises:
- `ValueError` if the key is already in the list.
"""
self._unique_guard(key)
self._list.append(key)
def extend(self, keys: Iterable[str]):
"""
Extend the list by multiple keys.
Args:
keys: Iterable of keys.
Raises:
- `ValueError` if one or more key is already in the list.
"""
self._unique_guard(*keys)
self._list.extend(keys)
def insert(
self, *keys: str, before: Optional[str] = None, after: Optional[str] = None
):
"""
Insert one or more keys. Either `before` or `after`, but not both, must be set
to determine position.
Args:
keys: One more keys to insert.
after: A key immediately after which the `keys` will be inserted.
before: A key immediately before which the `keys` are inserted.
Raises:
- `ValueError` if one or more key is already in the list.
- `ValueError` if `before` / `after` does not exist in the list.
- `ValueError` if an invalid combination of arguments is set.
"""
self._unique_guard(*keys)
if before is not None:
for key in keys[::-1]:
self._list.insert(self._list.index(before), key)
if after is not None:
raise ValueError("`after` must be None if `before` is set.")
if after is not None:
for key in keys[::-1]:
self._list.insert(self._list.index(after) + 1, key)
if before is not None:
raise ValueError("`before` must be None if `after` is set.")
if before is None and after is None:
raise ValueError("Either `before` or `after` must be set.")
def __getitem__(self, idx):
return self._list[idx]
def __len__(self):
return len(self._list)
def __iter__(self):
return iter(self._list)
def test_order():
order = Order(["dataset", "training", "validation", "logging"])
order.insert("architecture", before="training")
order.insert("environment", after="validation")
assert [item for item in order] == [
"dataset",
"architecture",
"training",
"validation",
"environment",
"logging",
]