time-split 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {time_split-0.3.0 → time_split-0.4.0}/PKG-INFO +2 -2
  2. {time_split-0.3.0 → time_split-0.4.0}/README.md +1 -1
  3. {time_split-0.3.0 → time_split-0.4.0}/pyproject.toml +2 -1
  4. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/__init__.py +1 -1
  5. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/_limits.py +26 -22
  6. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/_process_available.py +7 -5
  7. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/_schedule.py +3 -3
  8. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/_splitter.py +7 -6
  9. time_split-0.4.0/src/time_split/_compat.py +49 -0
  10. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_docstrings.py +18 -8
  11. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_frontend/_plot.py +8 -7
  12. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_frontend/_progress.py +3 -2
  13. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_frontend/_split.py +4 -4
  14. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_frontend/_to_string.py +1 -1
  15. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/sklearn/_impl.py +4 -4
  16. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/settings.py +7 -7
  17. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/types.py +3 -3
  18. {time_split-0.3.0 → time_split-0.4.0}/LICENSE.md +0 -0
  19. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/__init__.py +0 -0
  20. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/_datetime_index_like.py +0 -0
  21. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_backend/_span.py +0 -0
  22. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_frontend/__init__.py +0 -0
  23. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_frontend/_weight.py +0 -0
  24. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/_support.py +0 -0
  25. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/__init__.py +0 -0
  26. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/_log_progress.py +0 -0
  27. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/base.py +0 -0
  28. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/pandas/__init__.py +0 -0
  29. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/pandas/_impl.py +0 -0
  30. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/polars/__init__.py +0 -0
  31. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/polars/_impl.py +0 -0
  32. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/integration/sklearn/__init__.py +0 -0
  33. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/py.typed +0 -0
  34. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/support/__init__.py +0 -0
  35. {time_split-0.3.0 → time_split-0.4.0}/src/time_split/support/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: time-split
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Time-based k-fold validation splits for heterogeneous data.
5
5
  Home-page: https://github.com/rsundqvist/time-split
6
6
  Author: Richard Sundqvist
@@ -58,7 +58,7 @@ strong non-stationary characteristics.
58
58
  a CRON-expression, or a pre-defined list.
59
59
  - [Data selection](https://time-split.readthedocs.io/en/stable/guide/spans.html) based on a timedelta, or the splitting
60
60
  schedule itself.
61
- - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/flex.html) data limits for
61
+ - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/expand_limits.html) data limits for
62
62
  supported data types.
63
63
  - [Plotting function](https://time-split.readthedocs.io/en/stable/generated/time_split.html#time_split.plot) for
64
64
  visualization of folds. Display fold sizes (hour/row count), or
@@ -27,7 +27,7 @@ strong non-stationary characteristics.
27
27
  a CRON-expression, or a pre-defined list.
28
28
  - [Data selection](https://time-split.readthedocs.io/en/stable/guide/spans.html) based on a timedelta, or the splitting
29
29
  schedule itself.
30
- - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/flex.html) data limits for
30
+ - Automatically extract and [normalize](https://time-split.readthedocs.io/en/stable/guide/expand_limits.html) data limits for
31
31
  supported data types.
32
32
  - [Plotting function](https://time-split.readthedocs.io/en/stable/generated/time_split.html#time_split.plot) for
33
33
  visualization of folds. Display fold sizes (hour/row count), or
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "time-split"
3
- version = "0.3.0"
3
+ version = "0.4.0"
4
4
  description = "Time-based k-fold validation splits for heterogeneous data."
5
5
  authors = ["Richard Sundqvist <richard.sundqvist@live.se>"]
6
6
 
@@ -48,6 +48,7 @@ plotting = ["matplotlib", "seaborn"]
48
48
  croniter = "^2.0.3"
49
49
  pyarrow = ">=15.0.2,<17.0.0"
50
50
  polars = { version = "^0.20.19", extras = ["pandas"] }
51
+ numpy = "<2" # TODO: numpy 2.0
51
52
 
52
53
  [tool.poetry.group.docs]
53
54
  [tool.poetry.group.docs.dependencies]
@@ -11,6 +11,6 @@ __all__ = [
11
11
  "__version__", # Make MyPy happy
12
12
  ]
13
13
 
14
- __version__ = "0.3.0"
14
+ __version__ = "0.4.0"
15
15
 
16
16
  _logging.getLogger(__name__).addHandler(_logging.NullHandler())
@@ -4,8 +4,8 @@ from typing import NamedTuple
4
4
 
5
5
  from pandas import Timedelta, Timestamp
6
6
 
7
- from ..settings import auto_flex
8
- from ..types import Flex, TimedeltaTypes
7
+ from ..settings import auto_expand_limits
8
+ from ..types import ExpandLimits, TimedeltaTypes
9
9
 
10
10
  LimitsTuple = tuple[Timestamp, Timestamp]
11
11
  LevelTuple = tuple[TimedeltaTypes, TimedeltaTypes, TimedeltaTypes]
@@ -17,17 +17,21 @@ class _TimedeltaTuple(NamedTuple):
17
17
  tolerance: Timedelta
18
18
 
19
19
 
20
- def expand_limits(limits: LimitsTuple, *, flex: Flex | LevelTuple | Iterable[LevelTuple] = "auto") -> LimitsTuple:
20
+ def expand_limits(
21
+ limits: LimitsTuple,
22
+ spec: ExpandLimits | LevelTuple | Iterable[LevelTuple] = "auto",
23
+ ) -> LimitsTuple:
21
24
  """Derive the `"real"` bounds of `limits`.
22
25
 
23
26
  Args:
24
27
  limits: A tuple ``(min, max)`` of timestamps.
25
- flex: Flex arguments as described in the :ref:`User guide`. Also supports level-tuples
26
- ``[(start_at, round_to, tolerance)...]``. Passing ``flex=[settings.auto_flex.day, settings.auto_flex.hour]``
27
- is equivalent to ``flex='auto'``.
28
+ spec: Expansion spec as described in the :ref:`User guide`. Also supports level-tuples
29
+ ``[(start_at, round_to, tolerance)...]``. Passing
30
+ ``expand_limits=[settings.auto_expand_limits.day, settings.auto_expand_limits.hour]``
31
+ is equivalent to ``expand_limits='auto'``.
28
32
 
29
33
  Returns:
30
- Limits rounded according to the `flex`-argument.
34
+ Limits rounded according to the given specification.
31
35
 
32
36
  Raises:
33
37
  ValueError: For invalid limits.
@@ -38,23 +42,23 @@ def expand_limits(limits: LimitsTuple, *, flex: Flex | LevelTuple | Iterable[Lev
38
42
 
39
43
  Basic usage.
40
44
 
41
- >>> expand_limits(limits, flex="d")
45
+ >>> expand_limits(limits, "d")
42
46
  (Timestamp('2019-05-11 00:00:00'), Timestamp('2019-05-12 00:00:00'))
43
47
 
44
48
  You may specify a maximum "distance" that limits may be expanded.
45
49
 
46
- >>> expand_limits(limits, flex="d<1h")
50
+ >>> expand_limits(limits, "d<1h")
47
51
  (Timestamp('2019-05-11 00:00:00'), Timestamp('2019-05-11 22:05:30'))
48
52
 
49
53
  Limits will never be rounded in the "wrong" direction...
50
54
 
51
55
  >>> limits = Timestamp("2019-05-11"), Timestamp("2019-05-11 11:05:30")
52
- >>> expand_limits(limits, flex="d")
56
+ >>> expand_limits(limits, "d")
53
57
  (Timestamp('2019-05-11 00:00:00'), Timestamp('2019-05-11 11:05:30'))
54
58
 
55
59
  ...even if you make the tolerance large enough.
56
60
 
57
- >>> expand_limits(limits, flex="d<14h")
61
+ >>> expand_limits(limits, "d<14h")
58
62
  (Timestamp('2019-05-11 00:00:00'), Timestamp('2019-05-11 11:05:30'))
59
63
 
60
64
  """
@@ -62,20 +66,20 @@ def expand_limits(limits: LimitsTuple, *, flex: Flex | LevelTuple | Iterable[Lev
62
66
  msg = f"Bad limits. Expected limits[1] > limits[0], but got {limits=}."
63
67
  raise ValueError(msg)
64
68
 
65
- if flex is False:
69
+ if spec is False:
66
70
  return limits
67
71
 
68
- if flex is True or flex == "auto":
72
+ if spec is True or spec == "auto":
69
73
  return _from_levels(limits)
70
74
 
71
- if isinstance(flex, str):
72
- round_to, _, tolerance = flex.partition("<")
75
+ if isinstance(spec, str):
76
+ round_to, _, tolerance = spec.partition("<")
73
77
  level = _make_level(None, round_to=round_to.strip(), tolerance=tolerance.strip())
74
78
  return _apply(limits, level=level)
75
- if isinstance(flex, tuple):
76
- return _from_levels(limits, levels=[_make_level(*flex)])
79
+ if isinstance(spec, tuple):
80
+ return _from_levels(limits, levels=[_make_level(*spec)])
77
81
 
78
- return _from_levels(limits, levels=starmap(_make_level, flex))
82
+ return _from_levels(limits, levels=starmap(_make_level, spec))
79
83
 
80
84
 
81
85
  def _from_levels(limits: LimitsTuple, *, levels: Iterable[_TimedeltaTuple] | None = None) -> LimitsTuple:
@@ -106,7 +110,7 @@ def _apply(limits: LimitsTuple, *, level: _TimedeltaTuple) -> LimitsTuple:
106
110
  if abs(hi_ceil - hi) > level.tolerance:
107
111
  return limits
108
112
 
109
- if auto_flex.SANITY_CHECK:
113
+ if auto_expand_limits.SANITY_CHECK:
110
114
  if lo.round(level.round_to) != lo_floor:
111
115
  return limits
112
116
  if hi.round(level.round_to) != hi_ceil:
@@ -116,12 +120,12 @@ def _apply(limits: LimitsTuple, *, level: _TimedeltaTuple) -> LimitsTuple:
116
120
 
117
121
 
118
122
  def _levels_from_settings() -> list[_TimedeltaTuple]:
119
- day, hour = _make_level(*auto_flex.day), _make_level(*auto_flex.hour)
123
+ day, hour = _make_level(*auto_expand_limits.day), _make_level(*auto_expand_limits.hour)
120
124
  if day.round_to != Timedelta(days=1):
121
- msg = f"Invalid settings: {auto_flex.day=} must have round_to=1 day."
125
+ msg = f"Invalid settings: {auto_expand_limits.day=} must have round_to=1 day."
122
126
  raise ValueError(msg)
123
127
  if hour.round_to != Timedelta(hours=1):
124
- msg = f"Invalid settings: {auto_flex.hour=} must have round_to=1 hour."
128
+ msg = f"Invalid settings: {auto_expand_limits.hour=} must have round_to=1 hour."
125
129
  raise ValueError(msg)
126
130
  return [day, hour]
127
131
 
@@ -3,9 +3,10 @@ from typing import NamedTuple
3
3
  from pandas import DatetimeIndex, Timestamp, isna
4
4
 
5
5
  from .._support import handle_dask
6
- from ..types import DatetimeIterable, Flex
6
+ from ..types import DatetimeIterable, ExpandLimits
7
7
  from ._datetime_index_like import DatetimeIndexLike
8
- from ._limits import LimitsTuple, expand_limits
8
+ from ._limits import LimitsTuple
9
+ from ._limits import expand_limits as expand
9
10
 
10
11
 
11
12
  class ProcessAvailableResult(NamedTuple):
@@ -16,12 +17,13 @@ class ProcessAvailableResult(NamedTuple):
16
17
  expanded_limits: LimitsTuple
17
18
 
18
19
 
19
- def process_available(available: DatetimeIterable, *, flex: Flex) -> ProcessAvailableResult:
20
+ def process_available(available: DatetimeIterable, *, expand_limits: ExpandLimits) -> ProcessAvailableResult:
20
21
  """Process a user-given `available` argument.
21
22
 
22
23
  Args:
23
24
  available: Available data from user. May be ``None``
24
- flex: Flex-argument. Determines how much (if at all) to expand limits.
25
+ expand_limits: Expansion spec as described in the :ref:`User guide`. Determines how much (if at all) to expand
26
+ limits.
25
27
 
26
28
  Returns:
27
29
  A tuple ``(available, limits)``. Note that `available` will be ``None``, it has not been iterated over. This
@@ -49,7 +51,7 @@ def process_available(available: DatetimeIterable, *, flex: Flex) -> ProcessAvai
49
51
  # (croniter 1.4.1 + numpy 1.25.2): croniter cannot handle numpy.datetime64
50
52
  limits = Timestamp(min_dt), Timestamp(max_dt)
51
53
 
52
- expanded_limits = expand_limits(limits, flex=flex)
54
+ expanded_limits = expand(limits, spec=expand_limits)
53
55
  return ProcessAvailableResult(available_retval, limits=limits, expanded_limits=expanded_limits)
54
56
 
55
57
 
@@ -2,7 +2,7 @@ from typing import NamedTuple, cast, get_args
2
2
 
3
3
  from pandas import DatetimeIndex, NaT, Timedelta, Timestamp, date_range
4
4
 
5
- from ..types import DatetimeIterable, Flex, Schedule, TimedeltaTypes
5
+ from ..types import DatetimeIterable, ExpandLimits, Schedule, TimedeltaTypes
6
6
  from ._limits import LimitsTuple
7
7
  from ._process_available import ProcessAvailableResult, process_available
8
8
 
@@ -17,7 +17,7 @@ class MaterializedSchedule(NamedTuple):
17
17
 
18
18
 
19
19
  def materialize_schedule(
20
- schedule: Schedule, flex: Flex, *, available: DatetimeIterable | None = None
20
+ schedule: Schedule, expand_limits: ExpandLimits, *, available: DatetimeIterable | None = None
21
21
  ) -> MaterializedSchedule:
22
22
  """Materialize user schedule based on available data."""
23
23
  if available is None:
@@ -29,7 +29,7 @@ def materialize_schedule(
29
29
  except TypeError as e:
30
30
  raise ValueError("Schedule must be explicit when not bounded by an available range.") from e
31
31
 
32
- available_metadata = process_available(available, flex=flex)
32
+ available_metadata = process_available(available, expand_limits=expand_limits)
33
33
  min_dt, max_dt = available_metadata.expanded_limits
34
34
 
35
35
  if isinstance(schedule, str) and _cron_like(schedule):
@@ -4,7 +4,8 @@ from typing import cast, get_args
4
4
 
5
5
  from pandas import Timedelta, Timestamp
6
6
  from rics.misc import format_kwargs
7
- from rics.performance import format_seconds
7
+
8
+ from time_split._compat import fmt_sec
8
9
 
9
10
  from ..settings import misc
10
11
  from ..types import (
@@ -12,7 +13,7 @@ from ..types import (
12
13
  DatetimeIterable,
13
14
  DatetimeSplitBounds,
14
15
  DatetimeSplits,
15
- Flex,
16
+ ExpandLimits,
16
17
  Schedule,
17
18
  Span,
18
19
  TimedeltaTypes,
@@ -33,7 +34,7 @@ class DatetimeIndexSplitter:
33
34
  after: Span
34
35
  step: int
35
36
  n_splits: int
36
- flex: Flex
37
+ expand_limits: ExpandLimits
37
38
 
38
39
  def get_splits(self, available: DatetimeIterable | None = None) -> DatetimeSplits:
39
40
  """Compute a split of given user data."""
@@ -48,7 +49,7 @@ class DatetimeIndexSplitter:
48
49
  return splits, ms
49
50
 
50
51
  def _materialize_schedule(self, available: DatetimeIterable | None = None) -> MaterializedSchedule:
51
- ms = materialize_schedule(self.schedule, self.flex, available=available)
52
+ ms = materialize_schedule(self.schedule, self.expand_limits, available=available)
52
53
  if not ms.schedule.sort_values().equals(ms.schedule):
53
54
  raise ValueError(f"schedule must be sorted in ascending order; schedule={self.schedule!r} is not valid.")
54
55
 
@@ -137,10 +138,10 @@ class DatetimeIndexSplitter:
137
138
  if old == new:
138
139
  return retval + "<no change>"
139
140
  diff = (new - old).total_seconds()
140
- return retval + f"{_PrettyTimestamp(new).auto} ({'+' if diff > 0 else '-'}{format_seconds(abs(diff))})"
141
+ return retval + f"{_PrettyTimestamp(new).auto} ({'+' if diff > 0 else '-'}{fmt_sec(abs(diff))})"
141
142
 
142
143
  LOGGER.info(
143
- f"Available data limits have been expanded (since flex={self.flex!r}):\n"
144
+ f"Available data limits have been expanded (since expand_limits={self.expand_limits!r}):\n"
144
145
  f" start: {stringify(original[0], new=expanded[0])}\n"
145
146
  f" end: {stringify(original[1], new=expanded[1])}"
146
147
  )
@@ -0,0 +1,49 @@
1
+ """Vendored functions."""
2
+
3
+ from functools import wraps
4
+ from typing import Callable, ParamSpec, TypeVar
5
+ from warnings import warn
6
+
7
+ from rics.misc import tname
8
+
9
+ try:
10
+ from rics import strings
11
+
12
+ fmt_perf = strings.format_perf_counter
13
+ fmt_sec = strings.format_seconds
14
+ except ImportError:
15
+ from rics import performance
16
+
17
+ # TODO(0.5.0): Drop this.
18
+ fmt_perf = performance.format_perf_counter
19
+ fmt_sec = performance.format_seconds
20
+
21
+ P = ParamSpec("P")
22
+ T = TypeVar("T")
23
+
24
+ PARAMS = (("expand_limits", "flex"),)
25
+ WARNED: set[str] = set() # Minimize the amount of warnings - once per param is enough.
26
+
27
+
28
+ def deprecated_params(__func: Callable[P, T], /) -> Callable[P, T]:
29
+ @wraps(__func)
30
+ def wrap(*args: P.args, **kwargs: P.kwargs) -> T:
31
+ for new, old in PARAMS:
32
+ if old in kwargs:
33
+ if new in kwargs:
34
+ name = tname(__func, prefix_classname=True)
35
+ msg = f"Ambiguous call: {name}() does not accept both `{old}` and `{new}`."
36
+ raise TypeError(msg)
37
+
38
+ if old not in WARNED:
39
+ WARNED.add(old)
40
+
41
+ name = tname(__func, prefix_classname=True)
42
+ msg = f"{name}(): The `{old}` parameter is deprecated; use `{new}` instead."
43
+ warn(message=msg, category=DeprecationWarning, stacklevel=2)
44
+
45
+ kwargs[new] = kwargs.pop(old)
46
+
47
+ return __func(*args, **kwargs)
48
+
49
+ return wrap
@@ -1,6 +1,9 @@
1
- from typing import TypeVar
1
+ from typing import Callable, ParamSpec, TypeVar
2
2
 
3
- FuncType = TypeVar("FuncType") # No proper way to type this?
3
+ from time_split._compat import deprecated_params
4
+
5
+ P = ParamSpec("P")
6
+ T = TypeVar("T")
4
7
 
5
8
 
6
9
  def add_docstrings(**kwargs: str) -> None:
@@ -8,11 +11,17 @@ def add_docstrings(**kwargs: str) -> None:
8
11
  _DOCSTRINGS.update(kwargs)
9
12
 
10
13
 
11
- def docs(function: FuncType) -> FuncType:
14
+ def docs(__func: Callable[P, T], /) -> Callable[P, T]:
12
15
  """Add info the docstring of a function."""
13
- assert function.__doc__ is not None # noqa: S101
14
- function.__doc__ = function.__doc__.format(**_DOCSTRINGS)
15
- return function
16
+ assert __func.__doc__ is not None # noqa: S101
17
+ __func.__doc__ = __func.__doc__.format(**_DOCSTRINGS)
18
+
19
+ if isinstance(__func, type):
20
+ __func.__init__ = deprecated_params(__func.__init__)
21
+ else:
22
+ __func = deprecated_params(__func)
23
+
24
+ return __func
16
25
 
17
26
 
18
27
  _OFFSET = "pandas :ref:`offset alias <pandas:timeseries.offset_aliases>`"
@@ -27,9 +36,10 @@ _DOCSTRINGS = {
27
36
  "step": "Select a subset of folds, preferring folds later in the schedule.",
28
37
  "n_splits": "Maximum number of folds, preferring folds later in the schedule.",
29
38
  "available": "Binds `schedule` to a range.",
30
- "flex": f'A {_OFFSET} used to expand `available` data to its likely `"true"` limits. Pass ``False`` to disable.',
39
+ "expand_limits": f'A {_OFFSET} used to expand `available` data to its likely `"true"` limits. Pass ``False`` to disable.',
31
40
  "USER_GUIDE": (
32
- "For more information about the `schedule`, `before/after` and `flex`-arguments" ", see the :ref:`User guide`."
41
+ "For more information about the `schedule`, `before/after` and `expand_limits`-arguments"
42
+ ", see the :ref:`User guide`."
33
43
  ),
34
44
  "OFFSET": _OFFSET,
35
45
  "DatetimeIndexSplitterKwargs": "See :func:`~time_split.split`. The `available` keyword is managed by the integration.",
@@ -4,7 +4,8 @@ from typing import TYPE_CHECKING, Any, Literal
4
4
  import pandas as pd
5
5
  from pandas import Timestamp
6
6
  from rics.misc import format_kwargs, get_public_module
7
- from rics.performance import format_seconds
7
+
8
+ from time_split._compat import fmt_sec
8
9
 
9
10
  from .._backend import DatetimeIndexSplitter
10
11
  from .._backend._datetime_index_like import DatetimeIndexLike
@@ -16,7 +17,7 @@ from ..types import (
16
17
  DatetimeIterable,
17
18
  DatetimeSplitBounds,
18
19
  DatetimeSplits,
19
- Flex,
20
+ ExpandLimits,
20
21
  Schedule,
21
22
  Span,
22
23
  )
@@ -64,7 +65,7 @@ def plot(
64
65
  step: int = 1,
65
66
  n_splits: int = 0,
66
67
  available: DatetimeIterable | None = None,
67
- flex: Flex = "auto",
68
+ expand_limits: ExpandLimits = "auto",
68
69
  # Split plot args
69
70
  bar_labels: str | Rows | list[tuple[str, str]] | bool = True,
70
71
  show_removed: bool = False,
@@ -84,7 +85,7 @@ def plot(
84
85
  n_splits: {n_splits}
85
86
  available: {available} If `bar_labels` is given but is not a ``list``,
86
87
  this data will be used to compute fold sizes.
87
- flex: {flex}
88
+ expand_limits: {expand_limits}
88
89
  bar_labels: Labels to draw on the bars. If you pass a string, it will be interpreted as a time unit (see
89
90
  :ref:`pandas:timeseries.offset_aliases` for valid frequency strings). Bars will show the number of units
90
91
  contained. Pass `'rows'` to simply count the numbers of elements in `data` (if given). To write custom
@@ -114,7 +115,7 @@ def plot(
114
115
  after=after,
115
116
  step=step,
116
117
  n_splits=n_splits,
117
- flex=flex,
118
+ expand_limits=expand_limits,
118
119
  )
119
120
  plot_data = _get_plot_data(available, splitter, row_count_bin=row_count_bin, show_removed=show_removed)
120
121
 
@@ -207,10 +208,10 @@ def _plot_row_counts(ax: "Axes", row_count_bin: str | pd.Series, row_counts: pd.
207
208
  from numpy import diff, timedelta64
208
209
 
209
210
  row_counts = row_count_bin.sort_index()
210
- pretty = format_seconds(diff(row_counts.index).min() / timedelta64(1, "s"))
211
+ pretty = fmt_sec(diff(row_counts.index).min() / timedelta64(1, "s"))
211
212
  else:
212
213
  row_counts = row_counts.sort_index()
213
- pretty = format_seconds(pd.Timedelta(row_count_bin).total_seconds())
214
+ pretty = fmt_sec(pd.Timedelta(row_count_bin).total_seconds())
214
215
 
215
216
  row_counts = row_counts * (max(ax.get_yticks()) / row_counts.max()) # Normalize to fold number yaxis
216
217
  ax.fill_between(
@@ -6,7 +6,8 @@ from typing import Any, Generic
6
6
 
7
7
  import pandas as pd
8
8
  from rics.collections.dicts import flatten_dict
9
- from rics.performance import format_seconds
9
+
10
+ from time_split._compat import fmt_sec
10
11
 
11
12
  from ..settings import log_split_progress as settings
12
13
  from ..types import DatetimeSplitBounds, FormatMetrics, GetMetrics, LoggerArg, MetricsType, SplitProgressExtras
@@ -96,7 +97,7 @@ def log_split_progress(
96
97
  start_message=settings.START_MESSAGE,
97
98
  end_level=end_level,
98
99
  end_message=settings.END_MESSAGE,
99
- seconds_formatter=settings.SECONDS_FORMATTER or format_seconds,
100
+ seconds_formatter=settings.SECONDS_FORMATTER or fmt_sec,
100
101
  user_extra={} if extra is None else extra.copy(), # Not actually immutable; deepcopy can be very expensive.
101
102
  get_metrics=get_metrics,
102
103
  format_metrics=settings.FORMAT_METRICS or default_metrics_formatter,
@@ -1,6 +1,6 @@
1
1
  from .._backend import DatetimeIndexSplitter
2
2
  from .._docstrings import docs
3
- from ..types import DatetimeIterable, DatetimeSplits, Flex, Schedule, Span
3
+ from ..types import DatetimeIterable, DatetimeSplits, ExpandLimits, Schedule, Span
4
4
 
5
5
 
6
6
  @docs
@@ -12,7 +12,7 @@ def split(
12
12
  step: int = 1,
13
13
  n_splits: int = 0,
14
14
  available: DatetimeIterable | None = None,
15
- flex: Flex = "auto",
15
+ expand_limits: ExpandLimits = "auto",
16
16
  ) -> DatetimeSplits:
17
17
  """Create time-based cross-validation splits.
18
18
 
@@ -25,7 +25,7 @@ def split(
25
25
  step: {step}
26
26
  n_splits: {n_splits}
27
27
  available: {available} Passing a tuple ``(min, max)`` is enough.
28
- flex: {flex}
28
+ expand_limits: {expand_limits}
29
29
 
30
30
  {USER_GUIDE}
31
31
 
@@ -41,5 +41,5 @@ def split(
41
41
  after=after,
42
42
  step=step,
43
43
  n_splits=n_splits,
44
- flex=flex,
44
+ expand_limits=expand_limits,
45
45
  ).get_splits(available)
@@ -29,7 +29,7 @@ def to_string(
29
29
 
30
30
 
31
31
  def to_string(
32
- bounds: (DatetimeTypes | DatetimeSplitBounds | tuple[DatetimeTypes, DatetimeTypes, DatetimeTypes]),
32
+ bounds: DatetimeTypes | DatetimeSplitBounds | tuple[DatetimeTypes, DatetimeTypes, DatetimeTypes],
33
33
  mid: DatetimeTypes | None = None,
34
34
  end: DatetimeTypes | None = None,
35
35
  /,
@@ -10,7 +10,7 @@ from ...types import (
10
10
  DatetimeIterable,
11
11
  DatetimeSplits,
12
12
  DatetimeTypes,
13
- Flex,
13
+ ExpandLimits,
14
14
  MetricsType,
15
15
  Schedule,
16
16
  Span,
@@ -44,7 +44,7 @@ class ScikitLearnSplitter(BaseCrossValidator): # type: ignore[misc]
44
44
  after: {after}
45
45
  step: {step}
46
46
  n_splits: {n_splits}
47
- flex: {flex}
47
+ expand_limits: {expand_limits}
48
48
  log_progress: {log_progress}
49
49
  verify_xy: If ``True``, split X and y independently and verify that they are equal.
50
50
 
@@ -59,7 +59,7 @@ class ScikitLearnSplitter(BaseCrossValidator): # type: ignore[misc]
59
59
  before: Span = "7d",
60
60
  after: Span = 1,
61
61
  n_splits: int = 0,
62
- flex: Flex = "auto",
62
+ expand_limits: ExpandLimits = "auto",
63
63
  step: int = 1,
64
64
  log_progress: LogProgressArg[MetricsType] = False,
65
65
  verify_xy: bool = True,
@@ -71,7 +71,7 @@ class ScikitLearnSplitter(BaseCrossValidator): # type: ignore[misc]
71
71
  after=after,
72
72
  step=step,
73
73
  n_splits=n_splits,
74
- flex=flex,
74
+ expand_limits=expand_limits,
75
75
  )
76
76
  self.log_progress = log_progress
77
77
  self.verify_xy = verify_xy
@@ -5,14 +5,14 @@ import typing as _t
5
5
  from . import types as _tst
6
6
 
7
7
 
8
- class auto_flex: # noqa: N801
9
- """Configuration for the `'auto'` :attr:`~time_split.types.Flex` logic.
8
+ class auto_expand_limits: # noqa: N801
9
+ """Configuration for the `'auto'` :attr:`~time_split.types.ExpandLimits` logic.
10
10
 
11
- This class determines how ``(min, max)``-tuples are expanded when flexible bounds are enabled.
11
+ This class determines how ``(min, max)``-tuples are expanded when expand_limitsible bounds are enabled.
12
12
  """
13
13
 
14
14
  SANITY_CHECK: bool = True
15
- """If ``True``, use original limits if flexed limits do not pass sanity checks."""
15
+ """If ``True``, use original limits if expand_limitsed limits do not pass sanity checks."""
16
16
 
17
17
  @classmethod
18
18
  def set_level(
@@ -23,7 +23,7 @@ class auto_flex: # noqa: N801
23
23
  round_to: _tst.TimedeltaTypes,
24
24
  tolerance: _tst.TimedeltaTypes,
25
25
  ) -> None:
26
- """Set a :class:`Level` used by the auto-flex logic.
26
+ """Set a :class:`Level` used by the auto-expand_limits logic.
27
27
 
28
28
  Inputs are not verified until an actual split is made.
29
29
 
@@ -43,7 +43,7 @@ class auto_flex: # noqa: N801
43
43
  setattr(cls, level, level_tuple)
44
44
 
45
45
  class Level(_t.NamedTuple):
46
- """Level type used by :attr:`auto_flex`."""
46
+ """Level type used by :attr:`auto_expand_limits`."""
47
47
 
48
48
  start_at: _tst.TimedeltaTypes
49
49
  """Span size at which this level starts."""
@@ -114,7 +114,7 @@ class log_split_progress: # noqa: N801
114
114
  """
115
115
 
116
116
  SECONDS_FORMATTER: _t.Callable[[float], str] | None = None
117
- """A callable ``(seconds) -> formatted_seconds``. Use :func:`rics.performance.format_seconds` if ``None``.
117
+ """A callable ``(seconds) -> formatted_seconds``. Use :func:`rics.strings.format_seconds` if ``None``.
118
118
 
119
119
  Both ``seconds`` and ``formatted_seconds`` will be available to the :attr:`END_MESSAGE` message.
120
120
  """
@@ -18,8 +18,8 @@ Schedule: _t.TypeAlias = _pd.DatetimeIndex | DatetimeIterable | TimedeltaTypes
18
18
  """User schedule type."""
19
19
  Span = int | _t.Literal["all"] | TimedeltaTypes
20
20
  """User span type. Used to determine limits from the timestamps given by a :attr:`Schedule`."""
21
- Flex = bool | _t.Literal["auto"] | str
22
- """Flexibility frequency string for ``floor/ceil``. Pass ``False`` to disable."""
21
+ ExpandLimits = bool | _t.Literal["auto"] | str
22
+ """Limits flexibility spec for ``floor/ceil``. Pass ``False`` to disable."""
23
23
 
24
24
 
25
25
  class DatetimeSplitBounds(_t.NamedTuple):
@@ -62,7 +62,7 @@ class DatetimeIndexSplitterKwargs(_t.TypedDict, total=False):
62
62
  after: Span
63
63
  step: int
64
64
  n_splits: int
65
- flex: Flex
65
+ expand_limits: ExpandLimits
66
66
 
67
67
 
68
68
  LoggerArg = _logging.Logger | _logging.LoggerAdapter[_t.Any] | str
File without changes