Skip to content

Commit

Permalink
improves: improve on_elapsed func.
Browse files Browse the repository at this point in the history
  • Loading branch information
jlsneto committed Oct 12, 2024
1 parent 8e5d4fa commit 3f74616
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 62 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,5 @@ venv.bak/

CMakeLists.txt
MANIFEST.in
*.png
*.png
/local
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ cj.mathtools.theta_angle((2, 2), (0, -2)) # 135.0
### 🧰 Utils

```python

import cereja.utils.time
import cereja as cj

data = {"key1": 'value1', "key2": 'value2', "key3": 'value3', "key4": 'value4'}
Expand Down Expand Up @@ -322,7 +322,7 @@ cj.utils.list_methods(cj.Path)
cj.utils.string_to_literal('[1,2,3,4]')
# Output -> [1, 2, 3, 4]

cj.utils.time_format(3600)
cereja.utils.time.time_format(3600)
# Output -> '01:00:00'

cj.utils.truncate("Cereja is fun.", k=3)
Expand Down
3 changes: 2 additions & 1 deletion cereja/display/_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
from cereja.utils import is_iterable
from cereja.config.cj_types import Number
from cereja.system.unicode import Unicode
from cereja.utils import fill, time_format, get_instances_of, import_string
from cereja.utils import fill, get_instances_of, import_string
from cereja.utils.time import time_format
from cereja.mathtools import proportional, estimate, percent

__all__ = ["Progress", "State", "console"]
Expand Down
2 changes: 1 addition & 1 deletion cereja/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@
from . import typography
from . import decorators
from . import time
from .time import Timer, set_interval
from .time import Timer, set_interval, time_format
30 changes: 0 additions & 30 deletions cereja/utils/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import re
import string
import threading
import time
from collections import OrderedDict, defaultdict
from importlib import import_module
import importlib
Expand Down Expand Up @@ -58,7 +57,6 @@
"logger_level",
"module_references",
"set_log_level",
"time_format",
"string_to_literal",
"rescale_values",
"Source",
Expand Down Expand Up @@ -165,7 +163,6 @@ def split_sequence(seq: List[Any], is_break_fn: Callable) -> List[List[Any]]:

def map_values(obj: Union[dict, list, tuple, Iterator], fn: Callable) -> Union[dict, list, tuple, Iterator]:
fn_arg_count = SourceCodeAnalyzer(fn).argument_count
is_dict = isinstance(obj, dict)
if isinstance(obj, dict):
obj = obj.items()
_iter = iter(obj)
Expand Down Expand Up @@ -610,33 +607,6 @@ def get_attr_if_exists(obj: Any, attr: str) -> Union[object, None]:
return None


def time_format(seconds: float, format_="%H:%M:%S") -> Union[str, float]:
"""
Default format is '%H:%M:%S'
If the time exceeds 24 hours, it will return a format like 'X days HH:MM:SS'
>>> time_format(3600)
'01:00:00'
>>> time_format(90000)
'1 days 01:00:00'
"""
# Check if seconds is a valid number
if seconds >= 0 or seconds < 0:
# Calculate the absolute value of days
days = int(seconds // 86400)
# Format the time
time_ = time.strftime(format_, time.gmtime(abs(seconds) % 86400))
# Return with days if more than 24 hours
if days > 0:
return f"{days} days {time_}"
# Return the formatted time
if seconds < 0:
return f"-{time_}"
return time_
return seconds # Return NaN or any invalid input as it is


def fill(value: Union[list, str, tuple], max_size, with_=" ") -> Any:
"""
Calculates and adds value
Expand Down
8 changes: 5 additions & 3 deletions cereja/utils/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import functools
import threading
import time
import time as _time
from abc import abstractmethod
import abc
import logging
Expand Down Expand Up @@ -232,7 +231,8 @@ def on_elapsed(interval: float = 1,
use_threading: bool = False,
verbose: bool = False,
is_daemon: bool = False,
take_last=False):
take_last=False,
default=None):
"""
Run a function if the interval has elapsed
Expand All @@ -243,6 +243,8 @@ def on_elapsed(interval: float = 1,
@param is_daemon: If True, the thread will be a daemon
@param take_last: If the time has not run out, it stores and returns the last result of the function execution,
if the function returns anything.
@param default: return it if the time has not run out
"""

def decorator(func: Callable):
Expand Down Expand Up @@ -283,7 +285,7 @@ def run():
last_result = func(*args, **kwargs)
else:
return func(*args, **kwargs)
return last_result
return default or last_result

if use_threading:
import threading
Expand Down
115 changes: 91 additions & 24 deletions cereja/utils/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
import math
import threading
import time
import time as _time
from typing import Callable
from typing import Callable, Union

__all__ = ["Timer", "set_interval"]
__all__ = ["Timer", "set_interval", "time_format"]


class Timer:
Expand All @@ -33,12 +35,12 @@ class Timer:
_auto_reset (bool): Whether the timer should automatically reset after the interval has passed.
"""

def __init__(self, interval, start=True, auto_reset=False):
def __init__(self, interval=-1, start=True, auto_reset=False):
"""
Initialize the Timer.
Args:
interval (float): The time interval in seconds.
interval (float): The time interval in seconds, -1 means the timer has no stopping/reset condition.
start (bool): Whether to start the timer immediately. Default is True.
auto_reset (bool): Whether the timer should automatically reset after the interval has passed.
Default is False.
Expand All @@ -63,12 +65,19 @@ def __bool__(self):
return True
return False

def reset(self):
self.start()

def start(self):
"""
Start the timer by setting the start time to the current time.
"""
self._start = _time.time()

@property
def started(self) -> bool:
return self._start > 0

@property
def elapsed(self):
"""
Expand All @@ -77,7 +86,7 @@ def elapsed(self):
Returns:
float: The elapsed time in seconds.
"""
return _time.time() - self._start
return _time.time() - self._start if self.started else 0

@property
def remaining(self):
Expand All @@ -87,7 +96,7 @@ def remaining(self):
Returns:
float: The remaining time in seconds.
"""
return self._interval - self.elapsed
return max(self._interval - self.elapsed, 0) if self._interval > 0 else float("inf")

@property
def interval(self):
Expand All @@ -99,16 +108,6 @@ def interval(self):
"""
return self._interval

@interval.setter
def interval(self, value):
"""
Set the time interval.
Args:
value (float): The time interval in seconds.
"""
self._interval = value

@property
def auto_reset(self):
"""
Expand All @@ -119,15 +118,56 @@ def auto_reset(self):
"""
return self._auto_reset

@auto_reset.setter
def auto_reset(self, value):
"""
Set the auto reset setting.
@property
def is_timeout(self):
return bool(self)

Args:
value (bool): True to automatically reset the timer after the interval has passed, False otherwise.
"""
self._auto_reset = value
@property
def time_overflow(self):

return max(self.elapsed - self.interval, 0) if self._interval > 0 else 0

def __str__(self):
return time_format(self.elapsed)

def __repr__(self):
eta = "" if self._interval <= 0 else f", ETA={time_format(self.remaining)}"
return f"Timer(elapsed={self.__str__()}{eta})"


class TimeEstimate:
def __init__(self, size: int = None):
assert size is None or isinstance(size, (int, float)), TypeError(f"{size} isn't valid. Send a number!")
self._timer = Timer(start=True)
self._size = size or 0
self._total_times = 0

def set_time_it(self) -> float:
self._total_times += 1
return self._timer.elapsed

@property
def duration(self) -> float:
return self._timer.elapsed

@property
def duration_formated(self) -> str:
return time_format(self.duration)

@property
def eta(self):
if self._total_times == 0 or self._size == 0:
return float("inf")
else:
return max(((self._timer.elapsed / self._total_times) * self._size) - self._timer.elapsed, 0)

@property
def eta_formated(self):
return time_format(self.eta)

@property
def per_sec(self):
return math.ceil(self._total_times / max(self._timer.elapsed, 1))


class IntervalScheduler:
Expand Down Expand Up @@ -202,3 +242,30 @@ def set_interval(func: Callable, sec: float, is_daemon=False) -> IntervalSchedul
scheduler = IntervalScheduler(func, sec, is_daemon)
scheduler.start()
return scheduler


def time_format(seconds: float, format_="%H:%M:%S") -> Union[str, float]:
"""
Default format is '%H:%M:%S'
If the time exceeds 24 hours, it will return a format like 'X days HH:MM:SS'
>>> time_format(3600)
'01:00:00'
>>> time_format(90000)
'1 days 01:00:00'
"""
# Check if seconds is a valid number
if seconds >= 0 or seconds < 0:
# Calculate the absolute value of days
days = int(seconds // 86400)
# Format the time
time_ = time.strftime(format_, time.gmtime(abs(seconds) % 86400))
# Return with days if more than 24 hours
if days > 0:
return f"{days} days {time_}"
# Return the formatted time
if seconds < 0:
return f"-{time_}"
return time_
return seconds # Return NaN or any invalid input as it is

0 comments on commit 3f74616

Please sign in to comment.