File size: 3,381 Bytes
07423df |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
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",
]
|