pyintervals 1.0.3__tar.gz → 1.2.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.
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pyintervals
3
- Version: 1.0.3
3
+ Version: 1.2.0
4
4
  Summary: Efficient interval operations.
5
5
  License: MIT
6
6
  Keywords: interval,timespan
7
7
  Author: Serkan Kalay
8
8
  Author-email: serkanosmankalay@gmail.com
9
- Requires-Python: >=3.8.1,<4.0.0
9
+ Requires-Python: >=3.9,<4.0.0
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.9
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.13
17
17
  Requires-Dist: importlib-metadata (>=1,<5) ; python_version < "3.8"
18
18
  Requires-Dist: sortedcontainers (>=2.4.0,<3.0.0)
19
19
  Requires-Dist: sortedcontainers-stubs (>=2.4.2,<3.0.0)
20
+ Requires-Dist: twine (>=6.2.0,<7.0.0)
20
21
  Project-URL: Repository, https://github.com/serkankalay/pyintervals
21
22
  Description-Content-Type: text/x-rst
22
23
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pyintervals"
3
- version = "1.0.3"
3
+ version = "1.2.0"
4
4
  description = "Efficient interval operations."
5
5
  authors = ["Serkan Kalay <serkanosmankalay@gmail.com>"]
6
6
  license = "MIT"
@@ -24,10 +24,11 @@ keywords = [
24
24
  ]
25
25
 
26
26
  [tool.poetry.dependencies]
27
- python = "^3.8.1,<4.0"
27
+ python = ">=3.9,<4.0.0"
28
28
  importlib-metadata = {version = ">=1,<5", python = "<3.8"}
29
29
  sortedcontainers = "^2.4.0"
30
30
  sortedcontainers-stubs = "^2.4.2"
31
+ twine = "^6.2.0"
31
32
 
32
33
  [tool.poetry.group.test.dependencies]
33
34
  pytest = ">=7.0.1,<9.0.0"
@@ -68,4 +69,4 @@ add_imports = ['from __future__ import annotations']
68
69
 
69
70
  [build-system]
70
71
  requires = ["poetry-core"]
71
- build-backend = "poetry.core.masonry.api"
72
+ build-backend = "poetry.core.masonry.api"
@@ -2,4 +2,4 @@ from __future__ import annotations
2
2
 
3
3
  from datetime import datetime
4
4
 
5
- TIME_ZERO: datetime = datetime(1970, 1, 1)
5
+ TIME_ZERO: datetime = datetime.min
@@ -73,3 +73,15 @@ def contains(interval: Interval, other: Interval) -> bool:
73
73
 
74
74
  # We have at least one non-degenerate interval.
75
75
  return interval.start <= other.start and interval.end >= other.end
76
+
77
+
78
+ def intersection(
79
+ interval: Interval, other_interval: Interval
80
+ ) -> Interval | None:
81
+ if overlaps(interval, other_interval):
82
+ return Interval(
83
+ max([interval.start, other_interval.start]),
84
+ min([interval.end, other_interval.end]),
85
+ )
86
+ else:
87
+ return None
@@ -1,13 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from datetime import datetime
4
+ from datetime import datetime, timedelta
5
5
  from typing import Collection, Iterable, Sequence
6
+ from zoneinfo import ZoneInfo
6
7
 
7
8
  from sortedcontainers import SortedList
8
9
 
9
10
  from .constants import TIME_ZERO
10
- from .interval import Interval
11
+ from .interval import Interval, intersection
11
12
  from .search import weak_predecessor
12
13
  from .time_value_node import TimeValueNode, _simplify
13
14
 
@@ -59,19 +60,35 @@ def _relevant_nodes(
59
60
  )
60
61
 
61
62
 
63
+ def _area_during_interval(
64
+ handler: IntervalHandler,
65
+ during: Interval,
66
+ ) -> timedelta:
67
+ return sum(
68
+ (
69
+ interval.value * during.value * overlap.duration()
70
+ for interval in handler.intervals
71
+ if (overlap := intersection(during, interval))
72
+ ),
73
+ start=timedelta(0),
74
+ )
75
+
76
+
62
77
  @dataclass
63
78
  class IntervalHandler:
64
79
  __intervals: list[Interval]
65
80
  __projection_graph: SortedList[TimeValueNode]
66
81
 
67
- def __init__(self, intervals: Iterable[Interval] = []):
68
- self._initialize()
82
+ def __init__(
83
+ self, intervals: Iterable[Interval] = [], tz: ZoneInfo | None = None
84
+ ):
85
+ self._initialize(tz)
69
86
  self.add(intervals)
70
87
 
71
- def _initialize(self) -> None:
88
+ def _initialize(self, tz: ZoneInfo | None) -> None:
72
89
  self.__intervals = list()
73
90
  self.__projection_graph = SortedList(
74
- [TimeValueNode(time_point=TIME_ZERO)]
91
+ [TimeValueNode(time_point=TIME_ZERO.replace(tzinfo=tz))]
75
92
  )
76
93
 
77
94
  @property
@@ -104,3 +121,6 @@ class IntervalHandler:
104
121
 
105
122
  def value_at_time(self, when: datetime) -> float:
106
123
  return _active_node_at_time(self.__projection_graph, when).value
124
+
125
+ def get_area(self, during: Interval) -> timedelta:
126
+ return _area_during_interval(self, during)
File without changes
File without changes
File without changes