Switch datetime handling, var handling to corelibs libraries

Use external corelib libraries for datetime handling and var handling enum base.
This commit is contained in:
Clemens Schwaighofer
2025-11-19 13:03:52 +09:00
parent af7633183c
commit 06a17d7c30
8 changed files with 139 additions and 415 deletions

View File

@@ -4,6 +4,7 @@
> This is pre-production, location of methods and names of paths can change > This is pre-production, location of methods and names of paths can change
> >
> This will be split up into modules per file and this will be just a collection holder > This will be split up into modules per file and this will be just a collection holder
> See [Deprecated](#deprecated) below
This is a pip package that can be installed into any project and covers the following parts This is a pip package that can be installed into any project and covers the following parts
@@ -42,6 +43,15 @@ This is a pip package that can be installed into any project and covers the foll
- csv_handling/csv_interface: The CSV DictWriter interface is just in a very basic way implemented - csv_handling/csv_interface: The CSV DictWriter interface is just in a very basic way implemented
- script_handling/script_helpers: No idea if there is need for this, tests are written but not finished - script_handling/script_helpers: No idea if there is need for this, tests are written but not finished
## Deprecated
All content in this module will move to stand alone libraries, as of now the following entries have moved and will throw deprecated warnings if used
- var_handling.enum_base: corelibs-enum-base
- var_handling.var_helpers: corelibs-var
- datetime_handling: corelibs-datetime
- string_handling.text_colors: corelibs-text-colors
## UV setup ## UV setup
uv must be [installed](https://docs.astral.sh/uv/getting-started/installation/) uv must be [installed](https://docs.astral.sh/uv/getting-started/installation/)

View File

@@ -6,12 +6,20 @@ description = "Collection of utils for Python scripts"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = [ dependencies = [
"corelibs-datetime>=1.0.1",
"corelibs-enum-base>=1.0.0",
"corelibs-var>=1.0.0",
"cryptography>=46.0.3", "cryptography>=46.0.3",
"jmespath>=1.0.1", "jmespath>=1.0.1",
"jsonpath-ng>=1.7.0", "jsonpath-ng>=1.7.0",
"psutil>=7.0.0", "psutil>=7.0.0",
"requests>=2.32.4", "requests>=2.32.4",
] ]
# MARK: build system
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# set this to disable publish to pypi (pip) # set this to disable publish to pypi (pip)
# classifiers = ["Private :: Do Not Upload"] # classifiers = ["Private :: Do Not Upload"]
@@ -21,10 +29,10 @@ name = "opj-pypi"
url = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" url = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/"
publish-url = "https://git.egplusww.jp/api/packages/PyPI/pypi" publish-url = "https://git.egplusww.jp/api/packages/PyPI/pypi"
# MARK: build system [tool.uv.sources]
[build-system] corelibs-enum-base = { index = "opj-pypi" }
requires = ["hatchling"] corelibs-datetime = { index = "opj-pypi" }
build-backend = "hatchling.build" corelibs-var = { index = "opj-pypi" }
[dependency-groups] [dependency-groups]
dev = [ dev = [

View File

@@ -2,26 +2,13 @@
Various string based date/time helpers Various string based date/time helpers
""" """
import time as time_t
from datetime import datetime, time from datetime import datetime, time
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from warnings import deprecated
from typing import Callable from zoneinfo import ZoneInfo
from corelibs_datetime import datetime_helpers
DAYS_OF_WEEK_LONG_TO_SHORT: dict[str, str] = {
'Monday': 'Mon',
'Tuesday': 'Tue',
'Wednesay': 'Wed',
'Thursday': 'Thu',
'Friday': 'Fri',
'Saturday': 'Sat',
'Sunday': 'Sun',
}
DAYS_OF_WEEK_ISO: dict[int, str] = {
1: 'Mon', 2: 'Tue', 3: 'Wed', 4: 'Thu', 5: 'Fri', 6: 'Sat', 7: 'Sun'
}
DAYS_OF_WEEK_ISO_REVERSED: dict[str, int] = {value: key for key, value in DAYS_OF_WEEK_ISO.items()}
@deprecated("Use corelibs_datetime.datetime_helpers.create_time instead")
def create_time(timestamp: float, timestamp_format: str = "%Y-%m-%d %H:%M:%S") -> str: def create_time(timestamp: float, timestamp_format: str = "%Y-%m-%d %H:%M:%S") -> str:
""" """
just takes a timestamp and prints out humand readable format just takes a timestamp and prints out humand readable format
@@ -35,21 +22,17 @@ def create_time(timestamp: float, timestamp_format: str = "%Y-%m-%d %H:%M:%S") -
Returns: Returns:
str -- _description_ str -- _description_
""" """
return time_t.strftime(timestamp_format, time_t.localtime(timestamp)) return datetime_helpers.create_time(timestamp, timestamp_format)
@deprecated("Use corelibs_datetime.datetime_helpers.get_system_timezone instead")
def get_system_timezone(): def get_system_timezone():
"""Get system timezone using datetime's automatic detection""" """Get system timezone using datetime's automatic detection"""
# Get current time with system timezone # Get current time with system timezone
local_time = datetime.now().astimezone() return datetime_helpers.get_system_timezone()
# Extract timezone info
system_tz = local_time.tzinfo
timezone_name = str(system_tz)
return system_tz, timezone_name
@deprecated("Use corelibs_datetime.datetime_helpers.parse_timezone_data instead")
def parse_timezone_data(timezone_tz: str = '') -> ZoneInfo: def parse_timezone_data(timezone_tz: str = '') -> ZoneInfo:
""" """
parses a string to get the ZoneInfo parses a string to get the ZoneInfo
@@ -62,40 +45,10 @@ def parse_timezone_data(timezone_tz: str = '') -> ZoneInfo:
Returns: Returns:
ZoneInfo -- _description_ ZoneInfo -- _description_
""" """
try: return datetime_helpers.parse_timezone_data(timezone_tz)
return ZoneInfo(timezone_tz)
except (ZoneInfoNotFoundError, ValueError, TypeError):
# use default
time_tz, time_tz_str = get_system_timezone()
if time_tz is None:
return ZoneInfo('UTC')
# TODO build proper TZ lookup
tz_mapping = {
'JST': 'Asia/Tokyo',
'KST': 'Asia/Seoul',
'IST': 'Asia/Kolkata',
'CST': 'Asia/Shanghai', # Default to China for CST
'AEST': 'Australia/Sydney',
'AWST': 'Australia/Perth',
'EST': 'America/New_York',
'EDT': 'America/New_York',
'CDT': 'America/Chicago',
'MST': 'America/Denver',
'MDT': 'America/Denver',
'PST': 'America/Los_Angeles',
'PDT': 'America/Los_Angeles',
'GMT': 'UTC',
'UTC': 'UTC',
'CET': 'Europe/Berlin',
'CEST': 'Europe/Berlin',
'BST': 'Europe/London',
}
try:
return ZoneInfo(tz_mapping[time_tz_str])
except (ZoneInfoNotFoundError, IndexError) as e:
raise ValueError(f"No mapping for {time_tz_str}: {e}") from e
@deprecated("Use corelibs_datetime.datetime_helpers.get_datetime_iso8601 instead")
def get_datetime_iso8601(timezone_tz: str | ZoneInfo = '', sep: str = 'T', timespec: str = 'microseconds') -> str: def get_datetime_iso8601(timezone_tz: str | ZoneInfo = '', sep: str = 'T', timespec: str = 'microseconds') -> str:
""" """
set a datetime in the iso8601 format with microseconds set a datetime in the iso8601 format with microseconds
@@ -103,12 +56,13 @@ def get_datetime_iso8601(timezone_tz: str | ZoneInfo = '', sep: str = 'T', times
Returns: Returns:
str -- _description_ str -- _description_
""" """
# parse if this is a string try:
if isinstance(timezone_tz, str): return datetime_helpers.get_datetime_iso8601(timezone_tz, sep, timespec)
timezone_tz = parse_timezone_data(timezone_tz) except KeyError as e:
return datetime.now(timezone_tz).isoformat(sep=sep, timespec=timespec) raise ValueError(f"Deprecated ValueError, change to KeyError: {e}") from e
@deprecated("Use corelibs_datetime.datetime_helpers.validate_date instead")
def validate_date(date: str, not_before: datetime | None = None, not_after: datetime | None = None) -> bool: def validate_date(date: str, not_before: datetime | None = None, not_after: datetime | None = None) -> bool:
""" """
check if Y-m-d or Y/m/d are parsable and valid check if Y-m-d or Y/m/d are parsable and valid
@@ -119,20 +73,10 @@ def validate_date(date: str, not_before: datetime | None = None, not_after: date
Returns: Returns:
bool -- _description_ bool -- _description_
""" """
formats = ['%Y-%m-%d', '%Y/%m/%d'] return datetime_helpers.validate_date(date, not_before, not_after)
for __format in formats:
try:
__date = datetime.strptime(date, __format).date()
if not_before is not None and __date < not_before.date():
return False
if not_after is not None and __date > not_after.date():
return False
return True
except ValueError:
continue
return False
@deprecated("Use corelibs_datetime.datetime_helpers.parse_flexible_date instead")
def parse_flexible_date( def parse_flexible_date(
date_str: str, date_str: str,
timezone_tz: str | ZoneInfo | None = None, timezone_tz: str | ZoneInfo | None = None,
@@ -154,49 +98,14 @@ def parse_flexible_date(
Returns: Returns:
datetime | None -- _description_ datetime | None -- _description_
""" """
return datetime_helpers.parse_flexible_date(
date_str = date_str.strip() date_str,
timezone_tz,
# Try different parsing methods shift_time_zone
parsers: list[Callable[[str], datetime]] = [ )
# ISO 8601 format, also with missing "T"
lambda x: datetime.fromisoformat(x), # pylint: disable=W0108
lambda x: datetime.fromisoformat(x.replace(' ', 'T')), # pylint: disable=W0108
# Simple date format
lambda x: datetime.strptime(x, "%Y-%m-%d"),
# datetime without T
lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S"),
lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S.%f"),
# Alternative ISO formats (fallback)
lambda x: datetime.strptime(x, "%Y-%m-%dT%H:%M:%S"),
lambda x: datetime.strptime(x, "%Y-%m-%dT%H:%M:%S.%f"),
]
if timezone_tz is not None:
if isinstance(timezone_tz, str):
timezone_tz = parse_timezone_data(timezone_tz)
date_new = None
for parser in parsers:
try:
date_new = parser(date_str)
break
except ValueError:
continue
if date_new is not None:
if timezone_tz is not None:
# shift time zone (default), this will change the date
# if the date has no +HH:MM it will take the local time zone as base
if shift_time_zone:
return date_new.astimezone(timezone_tz)
# just add the time zone
return date_new.replace(tzinfo=timezone_tz)
return date_new
return None
@deprecated("Use corelibs_datetime.datetime_helpers.compare_dates instead")
def compare_dates(date1_str: str, date2_str: str) -> None | bool: def compare_dates(date1_str: str, date2_str: str) -> None | bool:
""" """
compare two dates, if the first one is newer than the second one return True compare two dates, if the first one is newer than the second one return True
@@ -210,23 +119,10 @@ def compare_dates(date1_str: str, date2_str: str) -> None | bool:
Returns: Returns:
None | bool -- _description_ None | bool -- _description_
""" """
return datetime_helpers.compare_dates(date1_str, date2_str)
try:
# Parse both dates
date1 = parse_flexible_date(date1_str)
date2 = parse_flexible_date(date2_str)
# Check if parsing was successful
if date1 is None or date2 is None:
return None
# Compare dates
return date1.date() > date2.date()
except ValueError:
return None
@deprecated("Use corelibs_datetime.datetime_helpers.find_newest_datetime_in_list instead")
def find_newest_datetime_in_list(date_list: list[str]) -> None | str: def find_newest_datetime_in_list(date_list: list[str]) -> None | str:
""" """
Find the newest date from a list of ISO 8601 formatted date strings. Find the newest date from a list of ISO 8601 formatted date strings.
@@ -238,31 +134,10 @@ def find_newest_datetime_in_list(date_list: list[str]) -> None | str:
Returns: Returns:
str: The date string with the newest/latest date, or None if list is empty or all dates are invalid str: The date string with the newest/latest date, or None if list is empty or all dates are invalid
""" """
if not date_list: return datetime_helpers.find_newest_datetime_in_list(date_list)
return None
valid_dates: list[tuple[str, datetime]] = []
for date_str in date_list:
try:
# Parse the date string and store both original string and parsed datetime
parsed_date = parse_flexible_date(date_str)
if parsed_date is None:
continue
valid_dates.append((date_str, parsed_date))
except ValueError:
# Skip invalid date strings
continue
if not valid_dates:
return None
# Find the date string with the maximum datetime value
newest_date_str: str = max(valid_dates, key=lambda x: x[1])[0]
return newest_date_str
@deprecated("Use corelibs_datetime.datetime_helpers.parse_day_of_week_range instead")
def parse_day_of_week_range(dow_days: str) -> list[tuple[int, str]]: def parse_day_of_week_range(dow_days: str) -> list[tuple[int, str]]:
""" """
Parse a day of week list/range string and return a list of tuples with day index and name. Parse a day of week list/range string and return a list of tuples with day index and name.
@@ -279,59 +154,13 @@ def parse_day_of_week_range(dow_days: str) -> list[tuple[int, str]]:
""" """
# we have Sun twice because it can be 0 or 7 # we have Sun twice because it can be 0 or 7
# Mon is 1 and Sun is 7, which is ISO standard # Mon is 1 and Sun is 7, which is ISO standard
dow_day = dow_days.split(",")
dow_day = [day.strip() for day in dow_day if day.strip()]
__out_dow_days: list[tuple[int, str]] = []
for __dow_day in dow_day:
# if we have a "-" in there fill
if "-" in __dow_day:
__dow_range = __dow_day.split("-")
__dow_range = [day.strip().capitalize() for day in __dow_range if day.strip()]
try: try:
start_day = DAYS_OF_WEEK_ISO_REVERSED[__dow_range[0]] return datetime_helpers.parse_day_of_week_range(dow_days)
end_day = DAYS_OF_WEEK_ISO_REVERSED[__dow_range[1]]
except KeyError:
# try long time
try:
start_day = DAYS_OF_WEEK_ISO_REVERSED[DAYS_OF_WEEK_LONG_TO_SHORT[__dow_range[0]]]
end_day = DAYS_OF_WEEK_ISO_REVERSED[DAYS_OF_WEEK_LONG_TO_SHORT[__dow_range[1]]]
except KeyError as e: except KeyError as e:
raise ValueError(f"Invalid day of week entry found: {__dow_day}: {e}") from e raise ValueError(f"Deprecated ValueError, change to KeyError: {e}") from e
# Check if this spans across the weekend (e.g., Fri-Mon)
if start_day > end_day:
# Handle weekend-spanning range: start_day to 7, then 1 to end_day
__out_dow_days.extend(
[
(i, DAYS_OF_WEEK_ISO[i])
for i in range(start_day, 8) # start_day to Sunday (7)
]
)
__out_dow_days.extend(
[
(i, DAYS_OF_WEEK_ISO[i])
for i in range(1, end_day + 1) # Monday (1) to end_day
]
)
else:
# Normal range: start_day to end_day
__out_dow_days.extend(
[
(i, DAYS_OF_WEEK_ISO[i])
for i in range(start_day, end_day + 1)
]
)
else:
try:
__out_dow_days.append((DAYS_OF_WEEK_ISO_REVERSED[__dow_day], __dow_day))
except KeyError as e:
raise ValueError(f"Invalid day of week entry found: {__dow_day}: {e}") from e
# if there are duplicates, alert
if len(__out_dow_days) != len(set(__out_dow_days)):
raise ValueError(f"Duplicate day of week entries found: {__out_dow_days}")
return __out_dow_days
@deprecated("Use corelibs_datetime.datetime_helpers.parse_time_range instead")
def parse_time_range(time_str: str, time_format: str = "%H:%M") -> tuple[time, time]: def parse_time_range(time_str: str, time_format: str = "%H:%M") -> tuple[time, time]:
""" """
Parse a time range string in the format "HH:MM-HH:MM" and return a tuple of two time objects. Parse a time range string in the format "HH:MM-HH:MM" and return a tuple of two time objects.
@@ -347,22 +176,13 @@ def parse_time_range(time_str: str, time_format: str = "%H:%M") -> tuple[time, t
Returns: Returns:
tuple[time, time] -- start time, end time: leading zeros formattd tuple[time, time] -- start time, end time: leading zeros formattd
""" """
__time_str = time_str.strip()
# split by "-"
__time_split = __time_str.split("-")
if len(__time_split) != 2:
raise ValueError(f"Invalid time block: {__time_str}")
try: try:
__time_start = datetime.strptime(__time_split[0], time_format).time() return datetime_helpers.parse_time_range(time_str, time_format)
__time_end = datetime.strptime(__time_split[1], time_format).time() except KeyError as e:
except ValueError as e: raise ValueError(f"Deprecated ValueError, change to KeyError: {e}") from e
raise ValueError(f"Invalid time block format [{__time_str}]: {e}") from e
if __time_start >= __time_end:
raise ValueError(f"Invalid time block set, start time after end time or equal: {__time_str}")
return __time_start, __time_end
@deprecated("Use corelibs_datetime.datetime_helpers.times_overlap_or_connect instead")
def times_overlap_or_connect(time1: tuple[time, time], time2: tuple[time, time], allow_touching: bool = False) -> bool: def times_overlap_or_connect(time1: tuple[time, time], time2: tuple[time, time], allow_touching: bool = False) -> bool:
""" """
Check if two time ranges overlap or connect Check if two time ranges overlap or connect
@@ -375,16 +195,10 @@ def times_overlap_or_connect(time1: tuple[time, time], time2: tuple[time, time],
Returns: Returns:
bool: True if ranges overlap or connect (based on allow_touching) bool: True if ranges overlap or connect (based on allow_touching)
""" """
start1, end1 = time1 return datetime_helpers.times_overlap_or_connect(time1, time2, allow_touching)
start2, end2 = time2
if allow_touching:
# Only check for actual overlap (touching is OK)
return start1 < end2 and start2 < end1
# Check for overlap OR touching
return start1 <= end2 and start2 <= end1
@deprecated("Use corelibs_datetime.datetime_helpers.is_time_in_range instead")
def is_time_in_range(current_time: str, start_time: str, end_time: str) -> bool: def is_time_in_range(current_time: str, start_time: str, end_time: str) -> bool:
""" """
Check if current_time is within start_time and end_time (inclusive) Check if current_time is within start_time and end_time (inclusive)
@@ -399,18 +213,10 @@ def is_time_in_range(current_time: str, start_time: str, end_time: str) -> bool:
bool -- _description_ bool -- _description_
""" """
# Convert string times to time objects # Convert string times to time objects
current = datetime.strptime(current_time, "%H:%M:%S").time() return datetime_helpers.is_time_in_range(current_time, start_time, end_time)
start = datetime.strptime(start_time, "%H:%M:%S").time()
end = datetime.strptime(end_time, "%H:%M:%S").time()
# Handle case where range crosses midnight (e.g., 22:00 to 06:00)
if start <= end:
# Normal case: start time is before end time
return start <= current <= end
# Crosses midnight: e.g., 22:00 to 06:00
return current >= start or current <= end
@deprecated("Use corelibs_datetime.datetime_helpers.reorder_weekdays_from_today instead")
def reorder_weekdays_from_today(base_day: str) -> dict[int, str]: def reorder_weekdays_from_today(base_day: str) -> dict[int, str]:
""" """
Reorder the days of the week starting from the specified base_day. Reorder the days of the week starting from the specified base_day.
@@ -422,18 +228,8 @@ def reorder_weekdays_from_today(base_day: str) -> dict[int, str]:
dict[int, str] -- A dictionary mapping day numbers to day names. dict[int, str] -- A dictionary mapping day numbers to day names.
""" """
try: try:
today_num = DAYS_OF_WEEK_ISO_REVERSED[base_day] return datetime_helpers.reorder_weekdays_from_today(base_day)
except KeyError:
try:
today_num = DAYS_OF_WEEK_ISO_REVERSED[DAYS_OF_WEEK_LONG_TO_SHORT[base_day]]
except KeyError as e: except KeyError as e:
raise ValueError(f"Invalid day name provided: {base_day}: {e}") from e raise ValueError(f"Deprecated ValueError, change to KeyError: {e}") from e
# Convert to list of tuples
items = list(DAYS_OF_WEEK_ISO.items())
# Reorder: from today onwards + from beginning to yesterday
reordered_items = items[today_num - 1:] + items[:today_num - 1]
# Convert back to dictionary
return dict(reordered_items)
# __END__ # __END__

View File

@@ -2,19 +2,22 @@
Convert timestamp strings with time units into seconds and vice versa. Convert timestamp strings with time units into seconds and vice versa.
""" """
from math import floor from warnings import deprecated
import re from corelibs_datetime import timestamp_convert
from corelibs.var_handling.var_helpers import is_float from corelibs_datetime.timestamp_convert import TimeParseError as NewTimeParseError, TimeUnitError as NewTimeUnitError
@deprecated("Use corelibs_datetime.timestamp_convert.TimeParseError instead")
class TimeParseError(Exception): class TimeParseError(Exception):
"""Custom exception for time parsing errors.""" """Custom exception for time parsing errors."""
@deprecated("Use corelibs_datetime.timestamp_convert.TimeUnitError instead")
class TimeUnitError(Exception): class TimeUnitError(Exception):
"""Custom exception for time parsing errors.""" """Custom exception for time parsing errors."""
@deprecated("Use corelibs_datetime.timestamp_convert.convert_to_seconds instead")
def convert_to_seconds(time_string: str | int | float) -> int: def convert_to_seconds(time_string: str | int | float) -> int:
""" """
Conver a string with time units into a seconds string Conver a string with time units into a seconds string
@@ -35,67 +38,15 @@ def convert_to_seconds(time_string: str | int | float) -> int:
# skip out if this is a number of any type # skip out if this is a number of any type
# numbers will br made float, rounded and then converted to int # numbers will br made float, rounded and then converted to int
if is_float(time_string): try:
return int(round(float(time_string))) return timestamp_convert.convert_to_seconds(time_string)
time_string = str(time_string) except NewTimeParseError as e:
raise TimeParseError(f"Deprecated, use corelibs_datetime.timestamp_convert.TimeParseError: {e}") from e
# Check if the time string is negative except NewTimeUnitError as e:
negative = time_string.startswith('-') raise TimeUnitError(f"Deprecated, use corelibs_datetime.timestamp_convert.TimeUnitError: {e}") from e
if negative:
time_string = time_string[1:] # Remove the negative sign for processing
# Define time unit conversion factors
unit_factors: dict[str, int] = {
'Y': 31536000, # 365 days * 86400 seconds/day
'M': 2592000 * 12, # 1 year in seconds (assuming 365 days per year)
'd': 86400, # 1 day in seconds
'h': 3600, # 1 hour in seconds
'm': 60, # minutes to seconds
's': 1 # 1 second in seconds
}
long_unit_names: dict[str, str] = {
'year': 'Y',
'years': 'Y',
'month': 'M',
'months': 'M',
'day': 'd',
'days': 'd',
'hour': 'h',
'hours': 'h',
'minute': 'm',
'minutes': 'm',
'min': 'm',
'second': 's',
'seconds': 's',
'sec': 's',
}
total_seconds = 0
seen_units: list[str] = [] # Track units that have been encountered
# Use regex to match number and time unit pairs
for match in re.finditer(r'(\d+)\s*([a-zA-Z]+)', time_string):
value, unit = int(match.group(1)), match.group(2)
# full name check, fallback to original name
unit = long_unit_names.get(unit.lower(), unit)
# Check for duplicate units
if unit in seen_units:
raise TimeParseError(f"Unit '{unit}' appears more than once.")
# Check invalid unit
if unit not in unit_factors:
raise TimeUnitError(f"Unit '{unit}' is not a valid unit name.")
# Add to total seconds based on the units
if unit in unit_factors:
total_seconds += value * unit_factors[unit]
seen_units.append(unit)
return -total_seconds if negative else total_seconds
@deprecated("Use corelibs_datetime.timestamp_convert.seconds_to_string instead")
def seconds_to_string(seconds: str | int | float, show_microseconds: bool = False) -> str: def seconds_to_string(seconds: str | int | float, show_microseconds: bool = False) -> str:
""" """
Convert seconds to compact human readable format (e.g., "1d 2h 3m 4.567s") Convert seconds to compact human readable format (e.g., "1d 2h 3m 4.567s")
@@ -111,46 +62,10 @@ def seconds_to_string(seconds: str | int | float, show_microseconds: bool = Fals
Returns: Returns:
str: Compact human readable time format str: Compact human readable time format
""" """
# if not int or float, return as is return timestamp_convert.seconds_to_string(seconds, show_microseconds)
if not isinstance(seconds, (int, float)):
return seconds
# Handle negative values
negative = seconds < 0
seconds = abs(seconds)
whole_seconds = int(seconds)
fractional = seconds - whole_seconds
days = whole_seconds // 86400
hours = (whole_seconds % 86400) // 3600
minutes = (whole_seconds % 3600) // 60
secs = whole_seconds % 60
parts: list[str] = []
if days > 0:
parts.append(f"{days}d")
if hours > 0:
parts.append(f"{hours}h")
if minutes > 0:
parts.append(f"{minutes}m")
# Handle seconds with fractional part
if fractional > 0:
if show_microseconds:
total_seconds = secs + fractional
formatted = f"{total_seconds:.6f}".rstrip('0').rstrip('.')
parts.append(f"{formatted}s")
else:
total_seconds = secs + fractional
formatted = f"{total_seconds:.3f}".rstrip('0').rstrip('.')
parts.append(f"{formatted}s")
elif secs > 0 or not parts:
parts.append(f"{secs}s")
result = " ".join(parts)
return f"-{result}" if negative else result
@deprecated("Use corelibs_datetime.timestamp_convert.convert_timestamp instead")
def convert_timestamp(timestamp: float | int | str, show_microseconds: bool = True) -> str: def convert_timestamp(timestamp: float | int | str, show_microseconds: bool = True) -> str:
""" """
format timestamp into human readable format. This function will add 0 values between set values format timestamp into human readable format. This function will add 0 values between set values
@@ -168,33 +83,6 @@ def convert_timestamp(timestamp: float | int | str, show_microseconds: bool = Tr
Returns: Returns:
str -- _description_ str -- _description_
""" """
if not isinstance(timestamp, (int, float)): return timestamp_convert.convert_timestamp(timestamp, show_microseconds)
return timestamp
# cut of the ms, but first round them up to four
__timestamp_ms_split = str(round(timestamp, 4)).split(".")
timestamp = int(__timestamp_ms_split[0])
negative = timestamp < 0
timestamp = abs(timestamp)
try:
ms = int(__timestamp_ms_split[1])
except IndexError:
ms = 0
timegroups = (86400, 3600, 60, 1)
output: list[int] = []
for i in timegroups:
output.append(int(floor(timestamp / i)))
timestamp = timestamp % i
# output has days|hours|min|sec ms
time_string = ""
if output[0]:
time_string = f"{output[0]}d "
if output[0] or output[1]:
time_string += f"{output[1]}h "
if output[0] or output[1] or output[2]:
time_string += f"{output[2]}m "
time_string += f"{output[3]}s"
if show_microseconds:
time_string += f" {ms}ms" if ms else " 0ms"
return f"-{time_string}" if negative else time_string
# __END__ # __END__

View File

@@ -2,31 +2,20 @@
Current timestamp strings and time zones Current timestamp strings and time zones
""" """
from datetime import datetime from warnings import deprecated
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError from zoneinfo import ZoneInfo
from corelibs_datetime import timestamp_strings
class TimestampStrings: class TimestampStrings(timestamp_strings.TimestampStrings):
""" """
set default time stamps set default time stamps
""" """
TIME_ZONE: str = 'Asia/Tokyo' TIME_ZONE: str = 'Asia/Tokyo'
@deprecated("Use corelibs_datetime.timestamp_strings.TimestampStrings instead")
def __init__(self, time_zone: str | ZoneInfo | None = None): def __init__(self, time_zone: str | ZoneInfo | None = None):
self.timestamp_now = datetime.now() super().__init__(time_zone)
# set time zone as string
time_zone = time_zone if time_zone is not None else self.TIME_ZONE
self.time_zone = str(time_zone) if not isinstance(time_zone, str) else time_zone
# set ZoneInfo type
try:
self.time_zone_zi = ZoneInfo(self.time_zone)
except ZoneInfoNotFoundError as e:
raise ValueError(f'Zone could not be loaded [{self.time_zone}]: {e}') from e
self.timestamp_now_tz = datetime.now(self.time_zone_zi)
self.today = self.timestamp_now.strftime('%Y-%m-%d')
self.timestamp = self.timestamp_now.strftime("%Y-%m-%d %H:%M:%S")
self.timestamp_tz = self.timestamp_now_tz.strftime("%Y-%m-%d %H:%M:%S %Z")
self.timestamp_file = self.timestamp_now.strftime("%Y-%m-%d_%H%M%S")
# __END__ # __END__

View File

@@ -3,7 +3,9 @@ Enum base classes
""" """
from enum import Enum from enum import Enum
from warnings import deprecated
from typing import Any from typing import Any
# from corelibs_enum_base.enum_base import EnumBase as CorelibsEnumBase
class EnumBase(Enum): class EnumBase(Enum):
@@ -14,6 +16,7 @@ class EnumBase(Enum):
""" """
@classmethod @classmethod
@deprecated("Use corelibs_enum_base.EnumBase instead")
def lookup_key(cls, enum_key: str): def lookup_key(cls, enum_key: str):
"""Lookup from key side (must be string)""" """Lookup from key side (must be string)"""
# if there is a ":", then this is legacy, replace with ___ # if there is a ":", then this is legacy, replace with ___
@@ -27,6 +30,7 @@ class EnumBase(Enum):
raise ValueError(f"Invalid key: {enum_key}") from e raise ValueError(f"Invalid key: {enum_key}") from e
@classmethod @classmethod
@deprecated("Use corelibs_enum_base.EnumBase instead")
def lookup_value(cls, enum_value: Any): def lookup_value(cls, enum_value: Any):
"""Lookup through value side""" """Lookup through value side"""
try: try:
@@ -35,6 +39,7 @@ class EnumBase(Enum):
raise ValueError(f"Invalid value: {enum_value}") from e raise ValueError(f"Invalid value: {enum_value}") from e
@classmethod @classmethod
@deprecated("Use corelibs_enum_base.EnumBase instead")
def from_any(cls, enum_any: Any): def from_any(cls, enum_any: Any):
""" """
This only works in the following order This only works in the following order
@@ -62,14 +67,17 @@ class EnumBase(Enum):
raise ValueError(f"Could not find as key or value: {enum_any}") from e raise ValueError(f"Could not find as key or value: {enum_any}") from e
return cls.lookup_value(enum_any) return cls.lookup_value(enum_any)
@deprecated("Use corelibs_enum_base.EnumBase instead")
def to_value(self) -> Any: def to_value(self) -> Any:
"""Convert to value""" """Convert to value"""
return self.value return self.value
@deprecated("Use corelibs_enum_base.EnumBase instead")
def to_lower_case(self) -> str: def to_lower_case(self) -> str:
"""return lower case""" """return lower case"""
return self.name.lower() return self.name.lower()
@deprecated("Use corelibs_enum_base.EnumBase instead")
def __str__(self) -> str: def __str__(self) -> str:
"""return [Enum].NAME like it was called with .name""" """return [Enum].NAME like it was called with .name"""
return self.name return self.name

View File

@@ -3,8 +3,11 @@ variable convert, check, etc helepr
""" """
from typing import Any from typing import Any
from warnings import deprecated
import corelibs_var.var_helpers
@deprecated("Use corelibs_var.var_helpers.is_int instead")
def is_int(string: Any) -> bool: def is_int(string: Any) -> bool:
""" """
check if a value is int check if a value is int
@@ -15,15 +18,10 @@ def is_int(string: Any) -> bool:
Returns: Returns:
bool -- _description_ bool -- _description_
""" """
try: return corelibs_var.var_helpers.is_int(string)
int(string)
return True
except TypeError:
return False
except ValueError:
return False
@deprecated("Use corelibs_var.var_helpers.is_float instead")
def is_float(string: Any) -> bool: def is_float(string: Any) -> bool:
""" """
check if a value is float check if a value is float
@@ -34,15 +32,10 @@ def is_float(string: Any) -> bool:
Returns: Returns:
bool -- _description_ bool -- _description_
""" """
try: return corelibs_var.var_helpers.is_float(string)
float(string)
return True
except TypeError:
return False
except ValueError:
return False
@deprecated("Use corelibs_var.var_helpers.str_to_bool instead")
def str_to_bool(string: str): def str_to_bool(string: str):
""" """
convert string to bool convert string to bool
@@ -56,10 +49,6 @@ def str_to_bool(string: str):
Returns: Returns:
_type_ -- _description_ _type_ -- _description_
""" """
if string == "True" or string == "true": return corelibs_var.var_helpers.str_to_bool(string)
return True
if string == "False" or string == "false":
return False
raise ValueError(f"Invalid boolean string: {string}")
# __END__ # __END__

36
uv.lock generated
View File

@@ -111,6 +111,9 @@ name = "corelibs"
version = "0.36.0" version = "0.36.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "corelibs-datetime" },
{ name = "corelibs-enum-base" },
{ name = "corelibs-var" },
{ name = "cryptography" }, { name = "cryptography" },
{ name = "jmespath" }, { name = "jmespath" },
{ name = "jsonpath-ng" }, { name = "jsonpath-ng" },
@@ -127,6 +130,9 @@ dev = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "corelibs-datetime", specifier = ">=1.0.1", index = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" },
{ name = "corelibs-enum-base", specifier = ">=1.0.0", index = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" },
{ name = "corelibs-var", specifier = ">=1.0.0", index = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" },
{ name = "cryptography", specifier = ">=46.0.3" }, { name = "cryptography", specifier = ">=46.0.3" },
{ name = "jmespath", specifier = ">=1.0.1" }, { name = "jmespath", specifier = ">=1.0.1" },
{ name = "jsonpath-ng", specifier = ">=1.7.0" }, { name = "jsonpath-ng", specifier = ">=1.7.0" },
@@ -141,6 +147,36 @@ dev = [
{ name = "pytest-cov", specifier = ">=6.2.1" }, { name = "pytest-cov", specifier = ">=6.2.1" },
] ]
[[package]]
name = "corelibs-datetime"
version = "1.0.1"
source = { registry = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" }
dependencies = [
{ name = "corelibs-var" },
]
sdist = { url = "https://git.egplusww.jp/api/packages/PyPI/pypi/files/corelibs-datetime/1.0.1/corelibs_datetime-1.0.1.tar.gz", hash = "sha256:ff58c6f824f35b87b1a5c153f65fdd82b65e42bb5a649d46d9115dc5fa61042f" }
wheels = [
{ url = "https://git.egplusww.jp/api/packages/PyPI/pypi/files/corelibs-datetime/1.0.1/corelibs_datetime-1.0.1-py3-none-any.whl", hash = "sha256:f1a4d431f9f913dd39976a119ff8a2db34e966c61b1775c26b0da72a8bdb5ec1" },
]
[[package]]
name = "corelibs-enum-base"
version = "1.0.0"
source = { registry = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" }
sdist = { url = "https://git.egplusww.jp/api/packages/PyPI/pypi/files/corelibs-enum-base/1.0.0/corelibs_enum_base-1.0.0.tar.gz", hash = "sha256:c696a297d88f674d40e5d190f396909b5f663a995ac735e545ceb5bb4907121d" }
wheels = [
{ url = "https://git.egplusww.jp/api/packages/PyPI/pypi/files/corelibs-enum-base/1.0.0/corelibs_enum_base-1.0.0-py3-none-any.whl", hash = "sha256:c305d4063c69021aaf9ef75fbcce961039dae3c3de7820febeac7082c998a1f8" },
]
[[package]]
name = "corelibs-var"
version = "1.0.0"
source = { registry = "https://git.egplusww.jp/api/packages/PyPI/pypi/simple/" }
sdist = { url = "https://git.egplusww.jp/api/packages/PyPI/pypi/files/corelibs-var/1.0.0/corelibs_var-1.0.0.tar.gz", hash = "sha256:b85d6fd3802a1b687290666e4b1dbb47cf9723aa72bf73eb004e9e4936776364" }
wheels = [
{ url = "https://git.egplusww.jp/api/packages/PyPI/pypi/files/corelibs-var/1.0.0/corelibs_var-1.0.0-py3-none-any.whl", hash = "sha256:a3546785bf9c94eec08b5c500b69b971e83e11d92bc0e4d3cbd9411a561fdbc2" },
]
[[package]] [[package]]
name = "coverage" name = "coverage"
version = "7.12.0" version = "7.12.0"