using pytables as a row-indexed data store. git-svn-id: https://bucket.mit.edu/svn/nilm/nilmdb@10754 ddd99763-3ecb-0310-9145-efcb8ce7c51ftags/bxinterval-last
@@ -194,7 +194,7 @@ class NilmDB(object): | |||||
return sorted(list(x) for x in result) | return sorted(list(x) for x in result) | ||||
def stream_create(self, path, layout_name, index = None): | |||||
def stream_create(self, path, layout_name): | |||||
"""Create a new table in the database. | """Create a new table in the database. | ||||
path: path to the data (e.g. '/newton/prep'). | path: path to the data (e.g. '/newton/prep'). | ||||
@@ -205,10 +205,6 @@ class NilmDB(object): | |||||
/newton/upstairs/raw | /newton/upstairs/raw | ||||
layout_name: one of the nilmdb.layout.layouts keys, e.g. 'PrepData' | layout_name: one of the nilmdb.layout.layouts keys, e.g. 'PrepData' | ||||
index: list of layout columns to be marked as PyTables indices. | |||||
If index = none, the 'timestamp' column is indexed if it exists. | |||||
Pass an empty list to prevent indexing. | |||||
""" | """ | ||||
if path[0] != '/': | if path[0] != '/': | ||||
raise ValueError("paths must start with /") | raise ValueError("paths must start with /") | ||||
@@ -236,22 +232,11 @@ class NilmDB(object): | |||||
# 3 months worth of data. It's OK if this is wrong. | # 3 months worth of data. It's OK if this is wrong. | ||||
exp_rows = nilmdb.layout.named[layout_name].rate_hz * 60*60*24*30*3 | exp_rows = nilmdb.layout.named[layout_name].rate_hz * 60*60*24*30*3 | ||||
# Create the table | |||||
table = self.h5file.createTable(group, node, | table = self.h5file.createTable(group, node, | ||||
description = desc, | description = desc, | ||||
expectedrows = exp_rows) | expectedrows = exp_rows) | ||||
# Create indices | |||||
try: | |||||
if index is None and "timestamp" in table.colnames: | |||||
index = [ "timestamp" ] | |||||
for ind in index: | |||||
print "skipping index creation" | |||||
table.cols._f_col(str(ind)).createIndex() | |||||
except KeyError as e: | |||||
# Remove this table if we got an error | |||||
self.h5file.removeNode(group, node) | |||||
raise e | |||||
# Insert into SQL database once the PyTables is happy | # Insert into SQL database once the PyTables is happy | ||||
with self.con as con: | with self.con as con: | ||||
con.execute("INSERT INTO streams (path, layout) VALUES (?,?)", | con.execute("INSERT INTO streams (path, layout) VALUES (?,?)", | ||||
@@ -25,7 +25,7 @@ class NilmApp(object): | |||||
self.db = db | self.db = db | ||||
version = "1.1" | version = "1.1" | ||||
class Root(NilmApp): | class Root(NilmApp): | ||||
"""Root application for NILM database""" | """Root application for NILM database""" | ||||
@@ -72,19 +72,12 @@ class Stream(NilmApp): | |||||
# /stream/create?path=/newton/prep&layout=PrepData | # /stream/create?path=/newton/prep&layout=PrepData | ||||
@cherrypy.expose | @cherrypy.expose | ||||
@cherrypy.tools.json_out() | @cherrypy.tools.json_out() | ||||
def create(self, path, layout, index = None): | |||||
def create(self, path, layout): | |||||
"""Create a new stream in the database. Provide path | """Create a new stream in the database. Provide path | ||||
and one of the nilmdb.layout.layouts keys. | and one of the nilmdb.layout.layouts keys. | ||||
index: list of layout columns to be marked as PyTables indices. | |||||
If index = none, the 'timestamp' column is indexed if it exists. | |||||
Pass an empty list to prevent indexing. | |||||
""" | """ | ||||
# Index needs to be a list, if it's not None | |||||
if (index is not None) and (not isinstance(index, list)): | |||||
index = [ index ] | |||||
try: | try: | ||||
return self.db.stream_create(path, layout, index) | |||||
return self.db.stream_create(path, layout) | |||||
except Exception as e: | except Exception as e: | ||||
message = sprintf("%s: %s", type(e).__name__, e.message) | message = sprintf("%s: %s", type(e).__name__, e.message) | ||||
raise cherrypy.HTTPError("400 Bad Request", message) | raise cherrypy.HTTPError("400 Bad Request", message) | ||||
@@ -179,7 +172,7 @@ class Stream(NilmApp): | |||||
result = self.db.stream_insert(path, parser) | result = self.db.stream_insert(path, parser) | ||||
except nilmdb.nilmdb.NilmDBError as e: | except nilmdb.nilmdb.NilmDBError as e: | ||||
raise cherrypy.HTTPError("400 Bad Request", e.message) | raise cherrypy.HTTPError("400 Bad Request", e.message) | ||||
return "ok" | return "ok" | ||||
class Exiter(object): | class Exiter(object): | ||||
@@ -201,7 +194,7 @@ class Server(object): | |||||
force_traceback = False # include traceback in all errors | force_traceback = False # include traceback in all errors | ||||
): | ): | ||||
self.version = version | self.version = version | ||||
# Need to wrap DB object in a serializer because we'll call | # Need to wrap DB object in a serializer because we'll call | ||||
# into it from separate threads. | # into it from separate threads. | ||||
self.embedded = embedded | self.embedded = embedded | ||||
@@ -12,7 +12,7 @@ stop= | |||||
verbosity=2 | verbosity=2 | ||||
#tests=tests/test_cmdline.py | #tests=tests/test_cmdline.py | ||||
#tests=tests/test_layout.py | #tests=tests/test_layout.py | ||||
tests=tests/test_interval.py | |||||
#tests=tests/test_interval.py | |||||
#tests=tests/test_client.py | #tests=tests/test_client.py | ||||
#tests=tests/test_timestamper.py | #tests=tests/test_timestamper.py | ||||
#tests=tests/test_serializer.py | #tests=tests/test_serializer.py | ||||
@@ -80,10 +80,6 @@ class TestClient(object): | |||||
# Bad layout type | # Bad layout type | ||||
with assert_raises(ClientError): | with assert_raises(ClientError): | ||||
client.stream_create("/newton/prep", "NoSuchLayout") | client.stream_create("/newton/prep", "NoSuchLayout") | ||||
# Bad index column | |||||
with assert_raises(ClientError) as e: | |||||
client.stream_create("/newton/prep", "PrepData", ["nonexistant"]) | |||||
in_("KeyError: nonexistant", str(e.exception)) | |||||
client.stream_create("/newton/prep", "PrepData") | client.stream_create("/newton/prep", "PrepData") | ||||
client.stream_create("/newton/raw", "RawData") | client.stream_create("/newton/raw", "RawData") | ||||
client.stream_create("/newton/zzz/rawnotch", "RawNotchedData") | client.stream_create("/newton/zzz/rawnotch", "RawNotchedData") | ||||
@@ -56,9 +56,6 @@ class Test00Nilmdb(object): # named 00 so it runs first | |||||
# Bad layout type | # Bad layout type | ||||
with assert_raises(ValueError): | with assert_raises(ValueError): | ||||
db.stream_create("/newton/prep", "NoSuchLayout") | db.stream_create("/newton/prep", "NoSuchLayout") | ||||
# Bad index columns | |||||
with assert_raises(KeyError): | |||||
db.stream_create("/newton/prep", "PrepData", ["nonexistant"]) | |||||
db.stream_create("/newton/prep", "PrepData") | db.stream_create("/newton/prep", "PrepData") | ||||
db.stream_create("/newton/raw", "RawData") | db.stream_create("/newton/raw", "RawData") | ||||
db.stream_create("/newton/zzz/rawnotch", "RawNotchedData") | db.stream_create("/newton/zzz/rawnotch", "RawNotchedData") | ||||
@@ -76,7 +73,7 @@ class Test00Nilmdb(object): # named 00 so it runs first | |||||
eq_(len(db.h5file.getNode("/newton/prep").cols), 9) | eq_(len(db.h5file.getNode("/newton/prep").cols), 9) | ||||
eq_(len(db.h5file.getNode("/newton/raw").cols), 7) | eq_(len(db.h5file.getNode("/newton/raw").cols), 7) | ||||
eq_(len(db.h5file.getNode("/newton/zzz/rawnotch").cols), 10) | eq_(len(db.h5file.getNode("/newton/zzz/rawnotch").cols), 10) | ||||
assert(db.h5file.getNode("/newton/prep").colindexed["timestamp"]) | |||||
assert(not db.h5file.getNode("/newton/prep").colindexed["timestamp"]) | |||||
assert(not db.h5file.getNode("/newton/prep").colindexed["p1"]) | assert(not db.h5file.getNode("/newton/prep").colindexed["p1"]) | ||||
# Set / get metadata | # Set / get metadata | ||||