Compare commits
4 Commits
nilmdb-1.8
...
nilmdb-1.8
Author | SHA1 | Date | |
---|---|---|---|
b89b945a0f | |||
bd7bdb2eb8 | |||
840cd2fd13 | |||
bbd59c8b50 |
@@ -1,5 +1,6 @@
|
|||||||
from nilmdb.utils.printf import *
|
from nilmdb.utils.printf import *
|
||||||
import nilmdb.utils.time
|
import nilmdb.utils.time
|
||||||
|
from nilmdb.utils.interval import Interval
|
||||||
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import argparse
|
import argparse
|
||||||
@@ -42,6 +43,8 @@ def setup(self, sub):
|
|||||||
group = cmd.add_argument_group("Misc options")
|
group = cmd.add_argument_group("Misc options")
|
||||||
group.add_argument("-T", "--timestamp-raw", action="store_true",
|
group.add_argument("-T", "--timestamp-raw", action="store_true",
|
||||||
help="Show raw timestamps when printing times")
|
help="Show raw timestamps when printing times")
|
||||||
|
group.add_argument("-o", "--optimize", action="store_true",
|
||||||
|
help="Optimize (merge adjacent) intervals")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
@@ -58,9 +61,16 @@ def cmd_intervals(self):
|
|||||||
time_string = nilmdb.utils.time.timestamp_to_human
|
time_string = nilmdb.utils.time.timestamp_to_human
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for (start, end) in self.client.stream_intervals(
|
intervals = ( Interval(start, end) for (start, end) in
|
||||||
self.args.path, self.args.start, self.args.end, self.args.diff):
|
self.client.stream_intervals(self.args.path,
|
||||||
printf("[ %s -> %s ]\n", time_string(start), time_string(end))
|
self.args.start,
|
||||||
|
self.args.end,
|
||||||
|
self.args.diff) )
|
||||||
|
if self.args.optimize:
|
||||||
|
intervals = nilmdb.utils.interval.optimize(intervals)
|
||||||
|
for i in intervals:
|
||||||
|
printf("[ %s -> %s ]\n", time_string(i.start), time_string(i.end))
|
||||||
|
|
||||||
except nilmdb.client.ClientError as e:
|
except nilmdb.client.ClientError as e:
|
||||||
self.die("error listing intervals: %s", str(e))
|
self.die("error listing intervals: %s", str(e))
|
||||||
|
|
||||||
|
@@ -84,10 +84,18 @@ class Stream(NilmApp):
|
|||||||
# Helpers
|
# Helpers
|
||||||
def _get_times(self, start_param, end_param):
|
def _get_times(self, start_param, end_param):
|
||||||
(start, end) = (None, None)
|
(start, end) = (None, None)
|
||||||
if start_param is not None:
|
try:
|
||||||
start = string_to_timestamp(start_param)
|
if start_param is not None:
|
||||||
if end_param is not None:
|
start = string_to_timestamp(start_param)
|
||||||
end = string_to_timestamp(end_param)
|
except Exception:
|
||||||
|
raise cherrypy.HTTPError("400 Bad Request", sprintf(
|
||||||
|
"invalid start (%s): must be a numeric timestamp", start_param))
|
||||||
|
try:
|
||||||
|
if end_param is not None:
|
||||||
|
end = string_to_timestamp(end_param)
|
||||||
|
except Exception:
|
||||||
|
raise cherrypy.HTTPError("400 Bad Request", sprintf(
|
||||||
|
"invalid end (%s): must be a numeric timestamp", end_param))
|
||||||
if start is not None and end is not None:
|
if start is not None and end is not None:
|
||||||
if start >= end:
|
if start >= end:
|
||||||
raise cherrypy.HTTPError(
|
raise cherrypy.HTTPError(
|
||||||
|
@@ -58,18 +58,11 @@ class Interval:
|
|||||||
raise IntervalError("not a subset")
|
raise IntervalError("not a subset")
|
||||||
return Interval(start, end)
|
return Interval(start, end)
|
||||||
|
|
||||||
def set_difference(a, b):
|
def _interval_math_helper(a, b, op, subset = True):
|
||||||
"""
|
"""Helper for set_difference, intersection functions,
|
||||||
Compute the difference (a \\ b) between the intervals in 'a' and
|
to compute interval subsets based on a math operator on ranges
|
||||||
the intervals in 'b'; i.e., the ranges that are present in 'self'
|
present in A and B. Subsets are computed from A, or new intervals
|
||||||
but not 'other'.
|
are generated if subset = False."""
|
||||||
|
|
||||||
'a' and 'b' must both be iterables.
|
|
||||||
|
|
||||||
Returns a generator that yields each interval in turn.
|
|
||||||
Output intervals are built as subsets of the intervals in the
|
|
||||||
first argument (a).
|
|
||||||
"""
|
|
||||||
# Iterate through all starts and ends in sorted order. Add a
|
# Iterate through all starts and ends in sorted order. Add a
|
||||||
# tag to the iterator so that we can figure out which one they
|
# tag to the iterator so that we can figure out which one they
|
||||||
# were, after sorting.
|
# were, after sorting.
|
||||||
@@ -84,31 +77,57 @@ def set_difference(a, b):
|
|||||||
# At each point, evaluate which type of end it is, to determine
|
# At each point, evaluate which type of end it is, to determine
|
||||||
# how to build up the output intervals.
|
# how to build up the output intervals.
|
||||||
a_interval = None
|
a_interval = None
|
||||||
b_interval = None
|
in_a = False
|
||||||
|
in_b = False
|
||||||
out_start = None
|
out_start = None
|
||||||
for (ts, k, i) in nilmdb.utils.iterator.imerge(a_iter, b_iter):
|
for (ts, k, i) in nilmdb.utils.iterator.imerge(a_iter, b_iter):
|
||||||
if k == 0:
|
if k == 0:
|
||||||
# start a interval
|
|
||||||
a_interval = i
|
a_interval = i
|
||||||
if b_interval is None:
|
in_a = True
|
||||||
out_start = ts
|
|
||||||
elif k == 1:
|
elif k == 1:
|
||||||
# start b interval
|
in_b = True
|
||||||
b_interval = i
|
|
||||||
if out_start is not None and out_start != ts:
|
|
||||||
yield a_interval.subset(out_start, ts)
|
|
||||||
out_start = None
|
|
||||||
elif k == 2:
|
elif k == 2:
|
||||||
# end a interval
|
in_a = False
|
||||||
if out_start is not None and out_start != ts:
|
|
||||||
yield a_interval.subset(out_start, ts)
|
|
||||||
out_start = None
|
|
||||||
a_interval = None
|
|
||||||
elif k == 3:
|
elif k == 3:
|
||||||
# end b interval
|
in_b = False
|
||||||
b_interval = None
|
include = op(in_a, in_b)
|
||||||
if a_interval:
|
if include and out_start is None:
|
||||||
out_start = ts
|
out_start = ts
|
||||||
|
elif not include:
|
||||||
|
if out_start is not None and out_start != ts:
|
||||||
|
if subset:
|
||||||
|
yield a_interval.subset(out_start, ts)
|
||||||
|
else:
|
||||||
|
yield Interval(out_start, ts)
|
||||||
|
out_start = None
|
||||||
|
|
||||||
|
def set_difference(a, b):
|
||||||
|
"""
|
||||||
|
Compute the difference (a \\ b) between the intervals in 'a' and
|
||||||
|
the intervals in 'b'; i.e., the ranges that are present in 'self'
|
||||||
|
but not 'other'.
|
||||||
|
|
||||||
|
'a' and 'b' must both be iterables.
|
||||||
|
|
||||||
|
Returns a generator that yields each interval in turn.
|
||||||
|
Output intervals are built as subsets of the intervals in the
|
||||||
|
first argument (a).
|
||||||
|
"""
|
||||||
|
return _interval_math_helper(a, b, (lambda a, b: a and not b))
|
||||||
|
|
||||||
|
def intersection(a, b):
|
||||||
|
"""
|
||||||
|
Compute the intersection between the intervals in 'a' and the
|
||||||
|
intervals in 'b'; i.e., the ranges that are present in both 'a'
|
||||||
|
and 'b'.
|
||||||
|
|
||||||
|
'a' and 'b' must both be iterables.
|
||||||
|
|
||||||
|
Returns a generator that yields each interval in turn.
|
||||||
|
Output intervals are built as subsets of the intervals in the
|
||||||
|
first argument (a).
|
||||||
|
"""
|
||||||
|
return _interval_math_helper(a, b, (lambda a, b: a and b))
|
||||||
|
|
||||||
def optimize(it):
|
def optimize(it):
|
||||||
"""
|
"""
|
||||||
|
@@ -242,6 +242,19 @@ class TestClient(object):
|
|||||||
in_("400 Bad Request", str(e.exception))
|
in_("400 Bad Request", str(e.exception))
|
||||||
in_("start must precede end", str(e.exception))
|
in_("start must precede end", str(e.exception))
|
||||||
|
|
||||||
|
# Invalid times in HTTP request
|
||||||
|
with assert_raises(ClientError) as e:
|
||||||
|
client.http.put("stream/insert", "", { "path": "/newton/prep",
|
||||||
|
"start": "asdf", "end": 0 })
|
||||||
|
in_("400 Bad Request", str(e.exception))
|
||||||
|
in_("invalid start", str(e.exception))
|
||||||
|
|
||||||
|
with assert_raises(ClientError) as e:
|
||||||
|
client.http.put("stream/insert", "", { "path": "/newton/prep",
|
||||||
|
"start": 0, "end": "asdf" })
|
||||||
|
in_("400 Bad Request", str(e.exception))
|
||||||
|
in_("invalid end", str(e.exception))
|
||||||
|
|
||||||
# Good content type
|
# Good content type
|
||||||
with assert_raises(ClientError) as e:
|
with assert_raises(ClientError) as e:
|
||||||
client.http.put("stream/insert", "",
|
client.http.put("stream/insert", "",
|
||||||
|
@@ -1011,6 +1011,18 @@ class TestCmdline(object):
|
|||||||
self.match("[ Thu, 01 Jan 2004 00:00:00.000000 +0000 -"
|
self.match("[ Thu, 01 Jan 2004 00:00:00.000000 +0000 -"
|
||||||
"> Sat, 01 Jan 2005 00:00:00.000000 +0000 ]\n")
|
"> Sat, 01 Jan 2005 00:00:00.000000 +0000 ]\n")
|
||||||
|
|
||||||
|
# optimize
|
||||||
|
self.ok("insert -s 01-01-2002 -e 01-01-2004 /diff/1 /dev/null")
|
||||||
|
self.ok("intervals /diff/1")
|
||||||
|
self.match("[ Sat, 01 Jan 2000 00:00:00.000000 +0000 -"
|
||||||
|
"> Thu, 01 Jan 2004 00:00:00.000000 +0000 ]\n"
|
||||||
|
"[ Thu, 01 Jan 2004 00:00:00.000000 +0000 -"
|
||||||
|
"> Sat, 01 Jan 2005 00:00:00.000000 +0000 ]\n")
|
||||||
|
self.ok("intervals /diff/1 --optimize")
|
||||||
|
self.ok("intervals /diff/1 -o")
|
||||||
|
self.match("[ Sat, 01 Jan 2000 00:00:00.000000 +0000 -"
|
||||||
|
"> Sat, 01 Jan 2005 00:00:00.000000 +0000 ]\n")
|
||||||
|
|
||||||
self.ok("destroy -R /diff/1")
|
self.ok("destroy -R /diff/1")
|
||||||
self.ok("destroy -R /diff/2")
|
self.ok("destroy -R /diff/2")
|
||||||
|
|
||||||
|
@@ -234,13 +234,16 @@ class TestInterval:
|
|||||||
x = makeset("[--)") & 1234
|
x = makeset("[--)") & 1234
|
||||||
|
|
||||||
def do_test(a, b, c, d):
|
def do_test(a, b, c, d):
|
||||||
# a & b == c
|
# a & b == c (using nilmdb.server.interval)
|
||||||
ab = IntervalSet()
|
ab = IntervalSet()
|
||||||
for x in b:
|
for x in b:
|
||||||
for i in (a & x):
|
for i in (a & x):
|
||||||
ab += i
|
ab += i
|
||||||
eq_(ab,c)
|
eq_(ab,c)
|
||||||
|
|
||||||
|
# a & b == c (using nilmdb.utils.interval)
|
||||||
|
eq_(IntervalSet(nilmdb.utils.interval.intersection(a,b)), c)
|
||||||
|
|
||||||
# a \ b == d
|
# a \ b == d
|
||||||
eq_(IntervalSet(nilmdb.utils.interval.set_difference(a,b)), d)
|
eq_(IntervalSet(nilmdb.utils.interval.set_difference(a,b)), d)
|
||||||
|
|
||||||
@@ -310,6 +313,17 @@ class TestInterval:
|
|||||||
eq_(nilmdb.utils.interval.set_difference(
|
eq_(nilmdb.utils.interval.set_difference(
|
||||||
a.intersection(list(c)[0]), b.intersection(list(c)[0])), d)
|
a.intersection(list(c)[0]), b.intersection(list(c)[0])), d)
|
||||||
|
|
||||||
|
# Fill out test coverage for non-subsets
|
||||||
|
def diff2(a,b, subset):
|
||||||
|
return nilmdb.utils.interval._interval_math_helper(
|
||||||
|
a, b, (lambda a, b: b and not a), subset=subset)
|
||||||
|
with assert_raises(nilmdb.utils.interval.IntervalError):
|
||||||
|
list(diff2(a,b,True))
|
||||||
|
list(diff2(a,b,False))
|
||||||
|
|
||||||
|
# Empty second set
|
||||||
|
eq_(nilmdb.utils.interval.set_difference(a, IntervalSet()), a)
|
||||||
|
|
||||||
# Empty second set
|
# Empty second set
|
||||||
eq_(nilmdb.utils.interval.set_difference(a, IntervalSet()), a)
|
eq_(nilmdb.utils.interval.set_difference(a, IntervalSet()), a)
|
||||||
|
|
||||||
|
@@ -110,6 +110,5 @@ class TestSerializer(Base):
|
|||||||
def test_iter(self):
|
def test_iter(self):
|
||||||
sp = nilmdb.utils.serializer_proxy
|
sp = nilmdb.utils.serializer_proxy
|
||||||
i = sp(ListLike)()
|
i = sp(ListLike)()
|
||||||
print iter(i)
|
|
||||||
eq_(list(i), [1,2,3,4,5])
|
eq_(list(i), [1,2,3,4,5])
|
||||||
eq_(i[3], 3)
|
eq_(i[3], 3)
|
||||||
|
Reference in New Issue
Block a user