Skip to content

Commit

Permalink
remove isodate dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
danholdaway committed Apr 4, 2024
1 parent ee9db37 commit 2931ac5
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 6 deletions.
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ install_requires =
PyYAML>=6.0
Jinja2>=3.1.2
click>=8.0
isodate>=0.6.1
tests_require =
pytest
flake8
Expand Down
3 changes: 2 additions & 1 deletion src/jcb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -25,6 +25,7 @@
'ObservationChronicle',
'process_satellite_chronicles',
'datetime_from_conf',
'duration_from_conf',
'parse_channels',
'parse_channels_set',
'abort_if',
Expand Down
3 changes: 1 addition & 2 deletions src/jcb/observation_chronicle/observation_chronicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from datetime import datetime
import os

import isodate
import jcb
import yaml

Expand All @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/jcb/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
86 changes: 85 additions & 1 deletion src/jcb/utilities/config_parsing.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# --------------------------------------------------------------------------------------------------


from datetime import datetime
from datetime import datetime, timedelta
import re

import jcb
Expand Down Expand Up @@ -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))


# --------------------------------------------------------------------------------------------------

0 comments on commit 2931ac5

Please sign in to comment.