From 9383f0c7f9bbf98c552f356144df22837c2d5a44 Mon Sep 17 00:00:00 2001 From: "C. Allwardt" <3979063+craig8@users.noreply.github.com> Date: Thu, 2 Nov 2023 12:14:52 -0700 Subject: [PATCH] Add sort capability to list adapter. --- ieee_2030_5/adapters/__init__.py | 26 +++++++++++++++++++++++++- ieee_2030_5/adapters/adapters.py | 11 ++++++----- ieee_2030_5/config.py | 2 +- ieee_2030_5/server/meteringfs.py | 19 ++++++++++++++++--- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/ieee_2030_5/adapters/__init__.py b/ieee_2030_5/adapters/__init__.py index c17f4ed..f60d52c 100644 --- a/ieee_2030_5/adapters/__init__.py +++ b/ieee_2030_5/adapters/__init__.py @@ -249,7 +249,11 @@ def get_resource_list(self, list_uri: str, start: int = 0, after: int = 0, - limit: int = 0) -> Union[m.List_type, m.SubscribableList]: + limit: int = 0, + sort_by: List[str] = [], + reverse: bool = False) -> Union[m.List_type, m.SubscribableList]: + if isinstance(sort_by, str): + sort_by = [sort_by] cls = self.get_type(list_uri) if cls is None: raise KeyError(f"Resource list {list_uri} not found in adapter") @@ -257,6 +261,26 @@ def get_resource_list(self, thelist = eval(f"m.{cls.__name__}List()") try: thecontainerlist = list(self._container_dict[list_uri].values()) + for sort in sort_by: + subobj = sort.split('.') + if len(subobj) == 2: + try: + thecontainerlist = sorted( + thecontainerlist, + key=lambda o: getattr(getattr(o, subobj[0]), subobj[1]), + reverse=reverse) + except AttributeError: + # happens when value is none + pass + elif len(subobj) == 1: + thecontainerlist = sorted(thecontainerlist, + key=lambda o: getattr(o, sort), + reverse=reverse) + else: + raise ValueError("Can only sort through single nested properties.") + # if "." in sort: + + # thecontainerlist = sorted(thecontainerlist, key=sort) thelist.href = list_uri thelist.all = len(thecontainerlist) if start == after == limit == 0: diff --git a/ieee_2030_5/adapters/adapters.py b/ieee_2030_5/adapters/adapters.py index 6a2a0c4..a9f5692 100644 --- a/ieee_2030_5/adapters/adapters.py +++ b/ieee_2030_5/adapters/adapters.py @@ -89,32 +89,33 @@ def create_mirror_meter_reading( location = mr_list_href # Current instantanious values. - if mmr.Reading is not None: + if mmr_input.Reading is not None: mmr.Reading.href = hrefs.SEP.join([mmr.href, "r"]) mmr.Reading.href = mmr.Reading.href.replace("mup", "upt") add_href(mmr.Reading.href, mmr.Reading) mr.ReadingLink = m.ReadingLink(mmr.Reading.href) # Mirror reading sets - if mmr.MirrorReadingSet: + if mmr_input.MirrorReadingSet: mrs_list_href = hrefs.SEP.join([mmr.href, "rs"]) rs_list_href = hrefs.SEP.join([mmr.href, "rs"]).replace("mup", "upt") mr.ReadingSetListLink = m.ReadingSetListLink(href=rs_list_href) ListAdapter.initialize_uri(mr.ReadingSetListLink.href, m.ReadingSet) - for mrs in mmr.MirrorReadingSet: + for mrs in mmr_input.MirrorReadingSet: + found_rs = False try: mrs_item = ListAdapter.get_by_mrid(mrs_list_href, mrs.mRID) mrs_item_index = ListAdapter.get_list(mrs_list_href).index(mrs_item) - was_updated = True + found_rs = True except NotFoundError: mrs_item = mrs mrs_item_index = ListAdapter.list_size(mrs_list_href) mrs_item.href = hrefs.SEP.join([mrs_list_href, str(mrs_item_index)]) ListAdapter.append(mrs_list_href, mrs_item) - if was_updated: + if found_rs: rs_item = ListAdapter.get(rs_list_href, mrs_item_index) rs_item.description = mrs_item.description rs_item.timePeriod = mrs_item.timePeriod diff --git a/ieee_2030_5/config.py b/ieee_2030_5/config.py index 2baf7df..72c9ba1 100644 --- a/ieee_2030_5/config.py +++ b/ieee_2030_5/config.py @@ -185,7 +185,7 @@ class ServerConfiguration: log_event_list_poll_rate: int = 900 device_capability_poll_rate: int = 900 - usage_point_post_rate: int = 300 + mirror_usage_point_post_rate: int = 300 end_device_list_poll_rate: int = 86400 # daily check-in generate_admin_cert: bool = False diff --git a/ieee_2030_5/server/meteringfs.py b/ieee_2030_5/server/meteringfs.py index 2c6131b..28f659b 100644 --- a/ieee_2030_5/server/meteringfs.py +++ b/ieee_2030_5/server/meteringfs.py @@ -39,14 +39,19 @@ def get(self) -> Response: parsed = hrefs.ParsedUsagePointHref(request.path) handled = False + sort_by = [] + reversed = True if parsed.has_reading_list(): + sort_by = "timePeriod.start" if handled := parsed.reading_index is not None: obj = adpt.ListAdapter.get(parsed.last_list(), parsed.reading_index) elif parsed.has_reading_set_list(): + sort_by = "timePeriod.start" if handled := parsed.reading_set_index is not None: obj = adpt.ListAdapter.get(parsed.last_list(), parsed.reading_set_index) + obj = sorted(obj, key="timePeriod.start") elif parsed.has_meter_reading_list(): if handled := parsed.has_reading_type(): obj = get_href(request.path) @@ -56,13 +61,16 @@ def get(self) -> Response: obj = adpt.ListAdapter.get_resource_list(request.path, start=start, limit=limit, - after=after) + after=after, + reverse=reversed) if not handled: obj = adpt.ListAdapter.get_resource_list(request.path, start=start, limit=limit, - after=after) + after=after, + sort_by=sort_by, + reverse=reversed) # # /upt # if not parsed.has_usage_point_index(): # obj = adpt.UsagePointAdapter.fetch_all(m.UsagePointList(request.path), @@ -99,7 +107,10 @@ def get(self) -> Response: if not mup_href.has_usage_point_index(): # /mup - mup = adpt.ListAdapter.get_resource_list(request.path) + mup: m.MirrorUsagePointList = adpt.ListAdapter.get_resource_list(request.path) + # Because our resource_list doesn't include other properties than the list we set + # them here before returning. + mup.pollRate = self.server_config.mirror_usage_point_post_rate else: # /mup_0 mup = adpt.ListAdapter.get(hrefs.DEFAULT_MUP_ROOT, mup_href.usage_point_index) @@ -121,6 +132,8 @@ def post(self) -> Response: # Creating a new mup if data_type == m.MirrorUsagePoint: + if data.postRate is None: + data.postRate = self.server_config.mirror_usage_point_post_rate result = adpt.create_mirror_usage_point(mup=data) #result = adpt.MirrorUsagePointAdapter.create(mup=data) else: