@@ -3,9 +3,9 @@ | |||
import nilmdb | |||
from nilmdb.utils.printf import * | |||
from nilmdb.utils import datetime_tz | |||
import nilmdb.utils.time | |||
import sys | |||
import re | |||
import argparse | |||
from argparse import ArgumentDefaultsHelpFormatter as def_form | |||
@@ -33,63 +33,11 @@ class Cmdline(object): | |||
def arg_time(self, toparse): | |||
"""Parse a time string argument""" | |||
try: | |||
return self.parse_time(toparse).totimestamp() | |||
return nilmdb.utils.time.parse_time(toparse).totimestamp() | |||
except ValueError as e: | |||
raise argparse.ArgumentTypeError(sprintf("%s \"%s\"", | |||
str(e), toparse)) | |||
def parse_time(self, toparse): | |||
""" | |||
Parse a free-form time string and return a datetime_tz object. | |||
If the string doesn't contain a timestamp, the current local | |||
timezone is assumed (e.g. from the TZ env var). | |||
""" | |||
# If string isn't "now" and doesn't contain at least 4 digits, | |||
# consider it invalid. smartparse might otherwise accept | |||
# empty strings and strings with just separators. | |||
if toparse != "now" and len(re.findall(r"\d", toparse)) < 4: | |||
raise ValueError("not enough digits for a timestamp") | |||
# Try to just parse the time as given | |||
try: | |||
return datetime_tz.datetime_tz.smartparse(toparse) | |||
except ValueError: | |||
pass | |||
# Try to extract a substring in a condensed format that we expect | |||
# to see in a filename or header comment | |||
res = re.search(r"(^|[^\d])(" # non-numeric or SOL | |||
r"(199\d|2\d\d\d)" # year | |||
r"[-/]?" # separator | |||
r"(0[1-9]|1[012])" # month | |||
r"[-/]?" # separator | |||
r"([012]\d|3[01])" # day | |||
r"[-T ]?" # separator | |||
r"([01]\d|2[0-3])" # hour | |||
r"[:]?" # separator | |||
r"([0-5]\d)" # minute | |||
r"[:]?" # separator | |||
r"([0-5]\d)?" # second | |||
r"([-+]\d\d\d\d)?" # timezone | |||
r")", toparse) | |||
if res is not None: | |||
try: | |||
return datetime_tz.datetime_tz.smartparse(res.group(2)) | |||
except ValueError: | |||
pass | |||
# Could also try to successively parse substrings, but let's | |||
# just give up for now. | |||
raise ValueError("unable to parse timestamp") | |||
def time_string(self, timestamp): | |||
""" | |||
Convert a Unix timestamp to a string for printing, using the | |||
local timezone for display (e.g. from the TZ env var). | |||
""" | |||
dt = datetime_tz.datetime_tz.fromtimestamp(timestamp) | |||
return dt.strftime("%a, %d %b %Y %H:%M:%S.%f %z") | |||
def parser_setup(self): | |||
self.parser = JimArgumentParser(add_help = False, | |||
formatter_class = def_form) | |||
@@ -45,7 +45,7 @@ def cmd_extract(self): | |||
if self.args.timestamp_raw: | |||
time_string = repr | |||
else: | |||
time_string = self.time_string | |||
time_string = nilmdb.utils.time.format_time | |||
if self.args.annotate: | |||
printf("# path: %s\n", self.args.path) | |||
@@ -2,6 +2,7 @@ from nilmdb.utils.printf import * | |||
import nilmdb | |||
import nilmdb.client | |||
import nilmdb.utils.timestamper as timestamper | |||
import nilmdb.utils.time | |||
import sys | |||
@@ -73,7 +74,7 @@ def cmd_insert(self): | |||
start = self.args.start | |||
else: | |||
try: | |||
start = self.parse_time(filename) | |||
start = nilmdb.utils.time.parse_time(filename) | |||
except ValueError: | |||
self.die("error extracting time from filename '%s'", | |||
filename) | |||
@@ -1,4 +1,5 @@ | |||
from nilmdb.utils.printf import * | |||
import nilmdb.utils.time | |||
import fnmatch | |||
import argparse | |||
@@ -57,7 +58,7 @@ def cmd_list(self): | |||
if self.args.timestamp_raw: | |||
time_string = repr | |||
else: | |||
time_string = self.time_string | |||
time_string = nilmdb.utils.time.format_time | |||
for (path, layout) in streams: | |||
if not (fnmatch.fnmatch(path, self.args.path) and | |||
@@ -0,0 +1,54 @@ | |||
from nilmdb.utils import datetime_tz | |||
import re | |||
def parse_time(toparse): | |||
""" | |||
Parse a free-form time string and return a datetime_tz object. | |||
If the string doesn't contain a timestamp, the current local | |||
timezone is assumed (e.g. from the TZ env var). | |||
""" | |||
# If string isn't "now" and doesn't contain at least 4 digits, | |||
# consider it invalid. smartparse might otherwise accept | |||
# empty strings and strings with just separators. | |||
if toparse != "now" and len(re.findall(r"\d", toparse)) < 4: | |||
raise ValueError("not enough digits for a timestamp") | |||
# Try to just parse the time as given | |||
try: | |||
return datetime_tz.datetime_tz.smartparse(toparse) | |||
except ValueError: | |||
pass | |||
# Try to extract a substring in a condensed format that we expect | |||
# to see in a filename or header comment | |||
res = re.search(r"(^|[^\d])(" # non-numeric or SOL | |||
r"(199\d|2\d\d\d)" # year | |||
r"[-/]?" # separator | |||
r"(0[1-9]|1[012])" # month | |||
r"[-/]?" # separator | |||
r"([012]\d|3[01])" # day | |||
r"[-T ]?" # separator | |||
r"([01]\d|2[0-3])" # hour | |||
r"[:]?" # separator | |||
r"([0-5]\d)" # minute | |||
r"[:]?" # separator | |||
r"([0-5]\d)?" # second | |||
r"([-+]\d\d\d\d)?" # timezone | |||
r")", toparse) | |||
if res is not None: | |||
try: | |||
return datetime_tz.datetime_tz.smartparse(res.group(2)) | |||
except ValueError: | |||
pass | |||
# Could also try to successively parse substrings, but let's | |||
# just give up for now. | |||
raise ValueError("unable to parse timestamp") | |||
def format_time(timestamp): | |||
""" | |||
Convert a Unix timestamp to a string for printing, using the | |||
local timezone for display (e.g. from the TZ env var). | |||
""" | |||
dt = datetime_tz.datetime_tz.fromtimestamp(timestamp) | |||
return dt.strftime("%a, %d %b %Y %H:%M:%S.%f %z") |
@@ -6,6 +6,7 @@ | |||
# foo.flush() | |||
from __future__ import print_function | |||
from __future__ import absolute_import | |||
import contextlib | |||
import time | |||
@@ -192,7 +192,23 @@ class TestCmdline(object): | |||
self.fail("extract --start 2000-01-01 --start 2001-01-02") | |||
self.contain("duplicated argument") | |||
def test_02_info(self): | |||
def test_02_parsetime(self): | |||
os.environ['TZ'] = "America/New_York" | |||
test = datetime_tz.datetime_tz.now() | |||
parse_time = nilmdb.utils.time.parse_time | |||
eq_(parse_time(str(test)), test) | |||
test = datetime_tz.datetime_tz.smartparse("20120405 1400-0400") | |||
eq_(parse_time("hi there 20120405 1400-0400 testing! 123"), test) | |||
eq_(parse_time("20120405 1800 UTC"), test) | |||
eq_(parse_time("20120405 1400-0400 UTC"), test) | |||
for badtime in [ "20120405 1400-9999", "hello", "-", "", "4:00" ]: | |||
with assert_raises(ValueError): | |||
x = parse_time(badtime) | |||
x = parse_time("now") | |||
eq_(parse_time("snapshot-20120405-140000.raw.gz"), test) | |||
eq_(parse_time("prep-20120405T1400"), test) | |||
def test_03_info(self): | |||
self.ok("info") | |||
self.contain("Server URL: http://localhost:12380/") | |||
self.contain("Client version: " + nilmdb.__version__) | |||
@@ -201,7 +217,7 @@ class TestCmdline(object): | |||
self.contain("Server database size") | |||
self.contain("Server database free space") | |||
def test_03_createlist(self): | |||
def test_04_createlist(self): | |||
# Basic stream tests, like those in test_client. | |||
# No streams | |||
@@ -277,7 +293,7 @@ class TestCmdline(object): | |||
self.fail("list /newton/prep --start 2020-01-01 --end 2000-01-01") | |||
self.contain("start must precede end") | |||
def test_04_metadata(self): | |||
def test_05_metadata(self): | |||
# Set / get metadata | |||
self.fail("metadata") | |||
self.fail("metadata --get") | |||
@@ -334,22 +350,6 @@ class TestCmdline(object): | |||
self.fail("metadata /newton/nosuchpath") | |||
self.contain("No stream at path /newton/nosuchpath") | |||
def test_05_parsetime(self): | |||
os.environ['TZ'] = "America/New_York" | |||
cmd = nilmdb.cmdline.Cmdline(None) | |||
test = datetime_tz.datetime_tz.now() | |||
eq_(cmd.parse_time(str(test)), test) | |||
test = datetime_tz.datetime_tz.smartparse("20120405 1400-0400") | |||
eq_(cmd.parse_time("hi there 20120405 1400-0400 testing! 123"), test) | |||
eq_(cmd.parse_time("20120405 1800 UTC"), test) | |||
eq_(cmd.parse_time("20120405 1400-0400 UTC"), test) | |||
for badtime in [ "20120405 1400-9999", "hello", "-", "", "4:00" ]: | |||
with assert_raises(ValueError): | |||
x = cmd.parse_time(badtime) | |||
x = cmd.parse_time("now") | |||
eq_(cmd.parse_time("snapshot-20120405-140000.raw.gz"), test) | |||
eq_(cmd.parse_time("prep-20120405T1400"), test) | |||
def test_06_insert(self): | |||
self.ok("insert --help") | |||