From 2931ac54304b0c7b0c28c753d81e72554f392fbd Mon Sep 17 00:00:00 2001 From: danholdaway Date: Thu, 4 Apr 2024 15:25:23 -0400 Subject: [PATCH] remove isodate dependency --- setup.cfg | 1 - src/jcb/__init__.py | 3 +- .../observation_chronicle.py | 3 +- src/jcb/renderer.py | 2 +- src/jcb/utilities/config_parsing.py | 86 ++++++++++++++++++- 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/setup.cfg b/setup.cfg index a9a586f..a06c3aa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,7 +21,6 @@ install_requires = PyYAML>=6.0 Jinja2>=3.1.2 click>=8.0 - isodate>=0.6.1 tests_require = pytest flake8 diff --git a/src/jcb/__init__.py b/src/jcb/__init__.py index 4cc3deb..057afd8 100644 --- a/src/jcb/__init__.py +++ b/src/jcb/__init__.py @@ -14,7 +14,7 @@ from .observation_chronicle.satellite_chronicle import process_satellite_chronicles from .renderer import render as render from .renderer import Renderer as Renderer -from .utilities.config_parsing import datetime_from_conf +from .utilities.config_parsing import datetime_from_conf, duration_from_conf from .utilities.parse_channels import parse_channels, parse_channels_set from .utilities.trapping import abort, abort_if @@ -25,6 +25,7 @@ 'ObservationChronicle', 'process_satellite_chronicles', 'datetime_from_conf', + 'duration_from_conf', 'parse_channels', 'parse_channels_set', 'abort_if', diff --git a/src/jcb/observation_chronicle/observation_chronicle.py b/src/jcb/observation_chronicle/observation_chronicle.py index cca8860..25c48cc 100644 --- a/src/jcb/observation_chronicle/observation_chronicle.py +++ b/src/jcb/observation_chronicle/observation_chronicle.py @@ -4,7 +4,6 @@ from datetime import datetime import os -import isodate import jcb import yaml @@ -25,7 +24,7 @@ def __init__(self, chronicle_path, window_begin, window_length): self.window_begin = datetime.strptime(window_begin, '%Y-%m-%dT%H:%M:%SZ') # Add window_length to window_begin - self.window_final = self.window_begin + isodate.parse_duration(window_length) + self.window_final = self.window_begin + jcb.duration_from_conf(window_length) # Save the most recent observer that was passed to the class. This can be used to avoid # re-precessing the chronicles if the same observer is used multiple times. diff --git a/src/jcb/renderer.py b/src/jcb/renderer.py index d061032..9ca4211 100644 --- a/src/jcb/renderer.py +++ b/src/jcb/renderer.py @@ -206,7 +206,7 @@ def render(self, algorithm): # Pointer to observers (mutable list so should not copy here) observers_dict = get_nested_dict(jedi_dict, observer_location) - # Loop over the observers and remove the non allowably components + # Loop over the observers and remove the non allowable components for observer_dict in observers_dict: for key in observer_dict: # Remove key if not in the observer components diff --git a/src/jcb/utilities/config_parsing.py b/src/jcb/utilities/config_parsing.py index 895f15c..e32656d 100644 --- a/src/jcb/utilities/config_parsing.py +++ b/src/jcb/utilities/config_parsing.py @@ -1,7 +1,7 @@ # -------------------------------------------------------------------------------------------------- -from datetime import datetime +from datetime import datetime, timedelta import re import jcb @@ -46,3 +46,87 @@ def datetime_from_conf(datetime_input): # -------------------------------------------------------------------------------------------------- + + +def check_duration_ordered(iso_duration): + + """ + Check if iso_duration characters is in correct order. The function will return True if the \ + characters in the iso_duration are in the correct order. The function is case sensitive. + + Args: + iso_duration (str): The iso_duration characters to check. + + Returns: + bool: True if the iso_duration is in correct order, False otherwise. + """ + + # Reference string for the correct order of the characters + reference = "PYMWDTHMS" + + # Strip non alpha characters from the string + iso_duration_letters = re.sub('[^a-zA-Z]', '', iso_duration) + + # Check that letters in the ios duration string are in the correct order + search_start = 0 + for char in iso_duration_letters: + # Try to find the current character in the reference string, starting from search_start + found_pos = reference.find(char, search_start) + if found_pos == -1: + # Character not found in the reference string, order is not preserved + return False + else: + # Move search_start to the position after the found character + search_start = found_pos + 1 + # All characters found in order, return True + return True + + +# -------------------------------------------------------------------------------------------------- + + +def duration_from_conf(iso_duration_input): + + """ + Convert an ISO 8601 duration string to a timedelta object. The string must be at least 2 + characters long to be a valid duration string. + + Args: + iso_duration_input (str or timedelta object): The ISO duration string to convert. + + Returns: + timedelta: The timedelta object. + """ + + # If the input is already a timedelta object then return it + if isinstance(iso_duration_input, timedelta): + return iso_duration_input + + # If not a string then abort + jcb.abort_if(not isinstance(iso_duration_input, str), + f"The ISO duration \'{iso_duration_input}\' is not a string.") + + # Strip non alpha characters from the string + jcb.abort_if(len(iso_duration_input) < 2, + f"The ISO duration \'{iso_duration_input}\' must be at least 2 characters long.") + + # Format is P[n]Y[n]M[n]W[n]DT[n]H[n]M[n]S. Use regex to extract the values + pattern = r'P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?T?(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?' + pattern_compile = re.compile(pattern) + years, months, weeks, days, hours, minutes, seconds = \ + pattern_compile.match(iso_duration_input).groups() + + # Assert that years and months are None + jcb.abort_if(years is not None or months is not None, + f"The ISO duration \'{iso_duration_input}\' must not have years or months. This " + "is not supported by the timedelta class in the Python standard.") + + # Create the timedelta object + return timedelta(weeks=int(weeks or 0), + days=int(days or 0), + hours=int(hours or 0), + minutes=int(minutes or 0), + seconds=int(seconds or 0)) + + +# --------------------------------------------------------------------------------------------------