Skip to content

Commit 4e9875e

Browse files
authored
Merge pull request #12 from GRIDAPPSD/der-updates
Der updates
2 parents ce1046e + 56b4f08 commit 4e9875e

28 files changed

+1704
-1418
lines changed

ieee_2030_5/adapters/__init__.py

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import typing
44
from dataclasses import dataclass, fields, is_dataclass
55
from enum import Enum
6-
from typing import Any, Dict, List, Optional, Protocol
6+
from typing import (Any, Dict, Generic, List, Optional, Protocol, Type,
7+
TypeVar, get_args, get_origin)
78

89
from blinker import Signal
910

1011
import ieee_2030_5.config as cfg
12+
import ieee_2030_5.hrefs as hrefs
1113
import ieee_2030_5.models as m
1214
from ieee_2030_5.certs import TLSRepository
1315
from ieee_2030_5.models.sep import List_type
@@ -58,6 +60,185 @@ def fetch_edev_all(self) -> List:
5860

5961
ready_signal = Signal("ready-signal")
6062

63+
T = TypeVar('T')
64+
C = TypeVar('C')
65+
D = TypeVar('D')
66+
67+
68+
class Adapter(Generic[T]):
69+
70+
def __init__(self, url_prefix: str, **kwargs):
71+
if "generic_type" not in kwargs:
72+
raise ValueError("Missing generic_type parameter")
73+
self._generic_type: Type = kwargs['generic_type']
74+
self._href_prefix: str = url_prefix
75+
self._current_index: int = -1
76+
self._item_list: Dict[int, T] = {}
77+
self._child_prefix: Dict[Type, str] = {}
78+
self._child_map: Dict[int, Dict[str, List[C]]] = {}
79+
80+
@property
81+
def href_prefix(self) -> str:
82+
return self._href_prefix
83+
84+
def add_container(self, child_type: Type, href_prefix: str):
85+
self._child_prefix[child_type] = href_prefix
86+
87+
def remove_child(self, parent: T, name: str, child: Any):
88+
found_index = self.fetch_index(parent)
89+
self._child_map[found_index][name].remove(child)
90+
91+
def remove_child_by_mrid(self, parent: T, name: str, mRID: str):
92+
93+
found_index = self.fetch_index(parent)
94+
95+
indexes = [index for index, x in enumerate(self._child_map[found_index][name]) if x.mRID == mRID]
96+
for index in sorted(indexes, reverse=True):
97+
self._child_map[found_index][name].pop(index)
98+
99+
def add_child(self, parent: T, name: str, child: Any, href: str = None):
100+
101+
# Make sure parent is in the Adapter by looking for it's index.
102+
found_index = self.fetch_index(parent)
103+
104+
# Deal with missing indexes
105+
if found_index not in self._child_map:
106+
self._child_map[found_index] = {}
107+
108+
if name not in self._child_map[found_index]:
109+
self._child_map[found_index][name] = []
110+
111+
if len(self._child_map[found_index][name]) > 0:
112+
if not isinstance(child, type(self._child_map[found_index][name][0])):
113+
raise ValueError(f"Children can only have single types {type(child)} != {type(self._child_map[found_index][name][0])}")
114+
if not child.href:
115+
if href:
116+
child.href = href
117+
else:
118+
child.href = hrefs.SEP.join([parent.href, name, str(len(self._child_map[found_index][name]))])
119+
self._child_map[found_index][name].append(child)
120+
121+
def fetch_children_by_parent_index(self, parent_index: int, child_type: Type) -> List[Type]:
122+
if child_type not in self._child_map[parent_index]:
123+
raise KeyError(f"No child object of type {child_type}")
124+
125+
return self._child_map[parent_index][child_type]
126+
127+
def fetch_children(self, parent: T, name: str, container: Optional[Type] = None) -> List[Type]:
128+
found_index = self.fetch_index(parent)
129+
# Should end with List if container is not None
130+
if container is not None:
131+
if not container.__class__.__name__.endswith("List"):
132+
raise ValueError(f"Invalid container, type must end in List")
133+
134+
try:
135+
children = self._child_map[found_index][name]
136+
except KeyError:
137+
children = []
138+
139+
retval = children
140+
141+
if container is not None:
142+
prop = container.__class__.__name__[:container.__class__.__name__.find("List")]
143+
setattr(container, prop, children)
144+
setattr(container, "results", len(children))
145+
setattr(container, "all", len(children))
146+
retval = container
147+
148+
return retval
149+
150+
def fetch_child(self, parent: T, name: str, index: int = 0) -> Type:
151+
return self.fetch_children(parent, name)[index]
152+
153+
def add(self, item: T):
154+
if not isinstance(item, self._generic_type):
155+
raise ValueError(f"Item {item} is not of type {self._generic_type}")
156+
157+
# Only replace if href is specified.
158+
if hasattr(item, 'href') and getattr(item, 'href') is None:
159+
setattr(item, 'href', hrefs.SEP.join([self._href_prefix, str(self._current_index + 1)]))
160+
self._current_index += 1
161+
self._item_list[self._current_index] = item
162+
163+
def fetch_all(self, instance: Optional[D] = None, start: int = 0, after: int = 0, limit: int = 1) -> D:
164+
165+
if instance is not None:
166+
if not instance.__class__.__name__.endswith("List"):
167+
raise ValueError("Must have List as the last portion of the name for instance")
168+
169+
prop_found = instance.__class__.__name__[:instance.__class__.__name__.find("List")]
170+
171+
items = list(self._item_list.values())
172+
all_len = len(items)
173+
all_results = len(items)
174+
all_items = items
175+
176+
if start > len(items):
177+
all_items = []
178+
all_results = 0
179+
else:
180+
if limit == 0:
181+
all_items = items[start:]
182+
else:
183+
all_items = items[start: start + limit]
184+
all_results = len(all_items)
185+
186+
setattr(instance, prop_found, all_items)
187+
setattr(instance, "all", all_len)
188+
setattr(instance, "results", all_results)
189+
else:
190+
instance = list(self._item_list.values())
191+
192+
return instance
193+
194+
def fetch_index(self, obj: T) -> int:
195+
found_index = -1
196+
for index, obj in self._item_list.items():
197+
if obj == obj:
198+
found_index = index
199+
break
200+
if found_index == -1:
201+
raise KeyError(f"Object {obj} not found in adapter")
202+
return found_index
203+
204+
def fetch(self, index: int):
205+
return self._item_list[index]
206+
207+
def fetch_by_mrid(self, mRID: str):
208+
for item in self._item_list:
209+
if not hasattr(item, 'mRID'):
210+
raise ValueError(f"Item of {type(T)} does not have mRID property")
211+
if item.mRID == mRID:
212+
return item
213+
214+
raise KeyError()
215+
216+
def size(self) -> int:
217+
return len(self._item_list)
218+
219+
def size_children(self, parent: T, name: str) -> int:
220+
return len(self.fetch_children(parent, name))
221+
222+
def fetch_child_index_by_mrid(self, parent: T, name: str, mRID: str) -> int:
223+
for index, child in enumerate(self.fetch_children(parent, name)):
224+
if child.mRID == mRID:
225+
return index
226+
227+
raise KeyError("mRID not found")
228+
229+
def replace_child(self, parent: T, name: str, index: int, child: Any):
230+
children = self.fetch_children(parent, name)
231+
if not type(child) == type(children[index]):
232+
return ValueError(f"Children should be of the same type {type(child)} is not {type(children[index])}")
233+
parent_index = self.fetch_index(parent)
234+
if not child.href:
235+
child.href = children[index].href
236+
self._child_map[parent_index][name][index] = child
237+
238+
239+
240+
241+
61242
class BaseAdapter:
62243
__count__: int = 0
63244
__server_configuration__: cfg.ServerConfiguration

0 commit comments

Comments
 (0)