Skip to content

Commit 4a5db62

Browse files
remove external inf dependency
1 parent fd3a709 commit 4a5db62

File tree

11 files changed

+237
-37
lines changed

11 files changed

+237
-37
lines changed

docs-md/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# boodle doodle

docs-md/modules.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
::: traces.timeseries
2+
3+
::: traces.timeseries.TimeSeries
4+
:docstring:
5+
:members:

docs-md/stylesheets/extra.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:root > * {
2+
--md-mermaid-label-bg-color: rgba(255, 255, 255, 0.9);
3+
}

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
site_name: traces
2+
docs_dir: ./docs-md
23
repo_url: https://github.com/stringertheory/traces
34
site_url: https://stringertheory.github.io/traces
45
site_description: A Python library for unevenly-spaced time series analysis
@@ -48,6 +49,7 @@ extra:
4849
link: https://pypi.org/project/traces
4950

5051
markdown_extensions:
52+
- mkautodoc
5153
- toc:
5254
permalink: true
5355
- pymdownx.arithmatex:

poetry.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ packages = [
1212

1313
[tool.poetry.dependencies]
1414
python = ">=3.8,<4.0"
15-
infinity = "^1.5"
1615
sortedcontainers = "^2.4.0"
1716

1817
[tool.poetry.group.dev.dependencies]
@@ -46,6 +45,7 @@ bump-my-version = "^0.17.3"
4645
notebook = "^7.0.7"
4746
deptry = "^0.12.0"
4847
python-dateutil = "^2.8.2"
48+
mkautodoc = "^0.2.0"
4949

5050
[tool.poetry.group.docs.dependencies]
5151
mkdocs = "^1.4.2"

tests/test_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from datetime import date, datetime, timedelta
22

33
import pytest
4-
from infinity import inf
54

65
import traces.utils as utils
6+
from traces.infinity import inf
77

88
timedelta_list = [
99
timedelta(hours=1),

traces/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from infinity import inf
2-
31
from . import decorators, operations
42
from .eventseries import EventSeries
53
from .histogram import Histogram
4+
from .infinity import inf
65
from .timeseries import TimeSeries
76
from .utils import datetime_range
87

traces/infinity.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""This module is derived from the `infinity` package (at
2+
https://pypi.org/project/infinity/ or
3+
https://github.com/kvesteri/infinity), which is licensed under the BSD
4+
3-Clause "New" or "Revised" License:
5+
6+
Copyright (c) 2014, Konsta Vesterinen
7+
All rights reserved.
8+
9+
Redistribution and use in source and binary forms, with or without modification,
10+
are permitted provided that the following conditions are met:
11+
12+
* Redistributions of source code must retain the above copyright notice, this
13+
list of conditions and the following disclaimer.
14+
15+
* Redistributions in binary form must reproduce the above copyright notice, this
16+
list of conditions and the following disclaimer in the documentation and/or
17+
other materials provided with the distribution.
18+
19+
* Neither the name of the {organization} nor the names of its
20+
contributors may be used to endorse or promote products derived from
21+
this software without specific prior written permission.
22+
23+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
34+
"""
35+
36+
from functools import total_ordering
37+
38+
39+
@total_ordering
40+
class Infinity:
41+
def __init__(self, positive=True):
42+
self.positive = positive
43+
44+
def __neg__(self):
45+
return Infinity(not self.positive)
46+
47+
def __gt__(self, other):
48+
if self == other:
49+
return False
50+
return self.positive
51+
52+
def __eq__(self, other):
53+
return (
54+
(
55+
isinstance(other, self.__class__)
56+
and other.positive == self.positive
57+
)
58+
or (self.positive and other == float("inf"))
59+
or (not self.positive and other == float("-inf"))
60+
)
61+
62+
def __ne__(self, other):
63+
return not (self == other)
64+
65+
def __bool__(self):
66+
return True
67+
68+
def __nonzero__(self):
69+
return True
70+
71+
def __str__(self):
72+
return "%sinf" % ("" if self.positive else "-")
73+
74+
def __float__(self):
75+
return float(str(self))
76+
77+
def __add__(self, other):
78+
if is_infinite(other) and other != self:
79+
return NotImplemented
80+
return self
81+
82+
def __radd__(self, other):
83+
return self
84+
85+
def __sub__(self, other):
86+
if is_infinite(other) and other == self:
87+
return NotImplemented
88+
return self
89+
90+
def __rsub__(self, other):
91+
return self
92+
93+
def timetuple(self):
94+
return ()
95+
96+
def __abs__(self):
97+
return self.__class__()
98+
99+
def __pos__(self):
100+
return self
101+
102+
def __div__(self, other):
103+
if is_infinite(other):
104+
return NotImplemented
105+
106+
return Infinity(
107+
other > 0 and self.positive or other < 0 and not self.positive
108+
)
109+
110+
def __rdiv__(self, other):
111+
return 0
112+
113+
def __repr__(self):
114+
return str(self)
115+
116+
__truediv__ = __div__
117+
__rtruediv__ = __rdiv__
118+
__floordiv__ = __div__
119+
__rfloordiv__ = __rdiv__
120+
121+
def __mul__(self, other):
122+
if other == 0:
123+
return NotImplemented
124+
return Infinity(
125+
other > 0 and self.positive or other < 0 and not self.positive
126+
)
127+
128+
__rmul__ = __mul__
129+
130+
def __pow__(self, other):
131+
if other == 0:
132+
return NotImplemented
133+
elif other == -self:
134+
return -0.0 if not self.positive else 0.0
135+
else:
136+
return Infinity()
137+
138+
def __rpow__(self, other):
139+
if other in (1, -1):
140+
return NotImplemented
141+
elif other == -self:
142+
return -0.0 if not self.positive else 0.0
143+
else:
144+
return Infinity()
145+
146+
def __hash__(self):
147+
return (self.__class__, self.positive).__hash__()
148+
149+
150+
inf = Infinity()
151+
152+
153+
def is_infinite(value):
154+
return value == inf or value == -inf

traces/timeseries.py

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@
1111
import itertools
1212
from queue import PriorityQueue
1313

14-
from infinity import inf
1514
from sortedcontainers import SortedDict
1615

17-
from . import histogram, operations, plot, utils
16+
from . import histogram, infinity, operations, plot, utils
1817

1918
NotGiven = object()
2019

@@ -164,9 +163,36 @@ def set(self, time, value, compact=False):
164163
self._d[time] = value
165164

166165
def set_interval(self, start, end, value, compact=False):
167-
"""Set the value for the time series on an interval. If compact is
168-
True, only set the value if it's different from what it would
169-
be anyway.
166+
"""Sets the value for the time series within a specified time
167+
interval.
168+
169+
Args:
170+
171+
start: The start time of the interval, inclusive
172+
end: The end time of the interval, exclusive.
173+
value: The value to set within the interval.
174+
compact (optional): If compact is True, only set the value
175+
if it's different from what it would be anyway. Defaults
176+
to False.
177+
178+
Raises:
179+
180+
ValueError: If the start time is equal or after the end
181+
time, indicating an invalid interval.
182+
183+
Example:
184+
185+
>>> ts = TimeSeries(data=[(1, 5), (3, 2), (5, 4), (6, 1)])
186+
>>> ts.set_interval(2, 6, 3)
187+
>>> ts
188+
TimeSeries({1: 5, 2: 3, 6: 1})
189+
190+
Note:
191+
192+
The method sets the value over the interval by removing
193+
measurements points from the time series between start and
194+
end (exclusive), rather than changing the value of any
195+
intermediate points to equal the value.
170196
171197
"""
172198
if start >= end:
@@ -183,13 +209,23 @@ def set_interval(self, start, end, value, compact=False):
183209
self.set(end, end_value, compact)
184210

185211
def compact(self):
186-
"""Convert this instance to a compact version: the value will be the
187-
same at all times, but repeated measurements are discarded.
212+
"""Convert this instance to a "compact" version: the value
213+
will be the same at all times, but repeated measurements are
214+
discarded.
188215
189-
"""
216+
Compacting the time series can significantly reduce the length
217+
and memory usage for data with many repeated values.
218+
219+
No arguments are required for this method, and it modifies the
220+
time series in place.
190221
191-
# todo: change to to_compact, do not modify in place. mark as deprecated
222+
Example:
223+
>>> ts = TimeSeries(data=[(1, 5), (2, 5), (5, 5), (6, 1)])
224+
>>> ts.compact()
225+
>>> ts
226+
TimeSeries({1: 5, 6: 1})
192227
228+
"""
193229
previous_value = object()
194230
redundant = []
195231
for time, value in self:
@@ -255,10 +291,8 @@ def __repr__(self):
255291
def format_item(item):
256292
return "{!r}: {!r}".format(*item)
257293

258-
return "{name}({{{items}}})".format(
259-
name=type(self).__name__,
260-
items=", ".join(format_item(_) for _ in self._d.items()),
261-
)
294+
items = dict(self._d.items())
295+
return f"{type(self).__name__}(default={self.default!r}, {items!r})"
262296

263297
def __str__(self):
264298
"""A human-readable string representation (truncated if it gets too
@@ -284,7 +318,9 @@ def format_item(item):
284318
else:
285319
items = ", ".join(format_item(_) for _ in self._d.items())
286320

287-
return f"{type(self).__name__}({{{items}}})"
321+
return f"{type(self).__name__}(default={self.default!r}, {{{items}}})"
322+
323+
# return f"{type(self).__name__}({{{items}}})"
288324

289325
def iterintervals(self, n=2):
290326
"""Iterate over groups of `n` consecutive measurement points in the
@@ -781,8 +817,8 @@ def distribution(
781817

782818
def n_points(
783819
self,
784-
start=-inf,
785-
end=+inf,
820+
start=-infinity.inf,
821+
end=+infinity.inf,
786822
mask=None,
787823
include_start=True,
788824
include_end=False,
@@ -1165,10 +1201,10 @@ def __ne__(self, other):
11651201

11661202
def _check_boundary(self, value, allow_infinite, lower_or_upper):
11671203
if lower_or_upper == "lower":
1168-
infinity_value = -inf
1204+
infinity_value = -infinity.inf
11691205
method_name = "first_key"
11701206
elif lower_or_upper == "upper":
1171-
infinity_value = inf
1207+
infinity_value = infinity.inf
11721208
method_name = "last_key"
11731209
else:
11741210
msg = (

0 commit comments

Comments
 (0)