Compare commits

..

7 Commits

7 changed files with 111 additions and 49 deletions

View File

@@ -123,14 +123,36 @@ class HTTPClient(object):
""" """
(response, isjson) = self._do_req(method, url, query, body, (response, isjson) = self._do_req(method, url, query, body,
stream = True, headers = headers) stream = True, headers = headers)
# Like the iter_lines function in Requests, but only splits on
# the specified line ending.
def lines(source, ending):
pending = None
for chunk in source:
if pending is not None:
chunk = pending + chunk
tmp = chunk.split(ending)
lines = tmp[:-1]
if chunk.endswith(ending):
pending = None
else:
pending = tmp[-1]
for line in lines:
yield line
if pending is not None: # pragma: no cover (missing newline)
yield pending
# Yield the chunks or lines as requested
if binary: if binary:
for chunk in response.iter_content(chunk_size = 65536): for chunk in response.iter_content(chunk_size = 65536):
yield chunk yield chunk
elif isjson: elif isjson:
for line in response.iter_lines(): for line in lines(response.iter_content(chunk_size = 1),
ending = '\r\n'):
yield json.loads(line) yield json.loads(line)
else: else:
for line in response.iter_lines(): for line in lines(response.iter_content(chunk_size = 65536),
ending = '\n'):
yield line yield line
def get_gen(self, url, params = None, binary = False): def get_gen(self, url, params = None, binary = False):

View File

@@ -72,10 +72,16 @@ class Complete(object): # pragma: no cover
path = parsed_args.path path = parsed_args.path
if not path: if not path:
return [] return []
return ( self.escape(k + '=' + v) results = []
for (k,v) in client.stream_get_metadata(path).iteritems() # prefix comes in as UTF-8, but results need to be Unicode,
if k.startswith(prefix) ) # weird. Still doesn't work in all cases, but that's bugs in
# argcomplete.
prefix = nilmdb.utils.unicode.decode(prefix)
for (k,v) in client.stream_get_metadata(path).iteritems():
kv = self.escape(k + '=' + v)
if kv.startswith(prefix):
results.append(kv)
return results
class Cmdline(object): class Cmdline(object):

View File

@@ -41,10 +41,10 @@ def cmd_metadata(self):
if self.args.set is not None or self.args.update is not None: if self.args.set is not None or self.args.update is not None:
# Either set, or update # Either set, or update
if self.args.set is not None: if self.args.set is not None:
keyvals = self.args.set keyvals = map(nilmdb.utils.unicode.decode, self.args.set)
handler = self.client.stream_set_metadata handler = self.client.stream_set_metadata
else: else:
keyvals = self.args.update keyvals = map(nilmdb.utils.unicode.decode, self.args.update)
handler = self.client.stream_update_metadata handler = self.client.stream_update_metadata
# Extract key=value pairs # Extract key=value pairs
@@ -62,7 +62,9 @@ def cmd_metadata(self):
self.die("error setting/updating metadata: %s", str(e)) self.die("error setting/updating metadata: %s", str(e))
elif self.args.delete is not None: elif self.args.delete is not None:
# Delete (by setting values to empty strings) # Delete (by setting values to empty strings)
keys = self.args.delete or None keys = None
if self.args.delete:
keys = map(nilmdb.utils.unicode.decode, self.args.delete)
try: try:
data = self.client.stream_get_metadata(self.args.path, keys) data = self.client.stream_get_metadata(self.args.path, keys)
for key in data: for key in data:
@@ -72,7 +74,9 @@ def cmd_metadata(self):
self.die("error deleting metadata: %s", str(e)) self.die("error deleting metadata: %s", str(e))
else: else:
# Get (or unspecified) # Get (or unspecified)
keys = self.args.get or None keys = None
if self.args.get:
keys = map(nilmdb.utils.unicode.decode, self.args.get)
try: try:
data = self.client.stream_get_metadata(self.args.path, keys) data = self.client.stream_get_metadata(self.args.path, keys)
except nilmdb.client.ClientError as e: except nilmdb.client.ClientError as e:
@@ -81,4 +85,6 @@ def cmd_metadata(self):
# Print nonexistant keys as having empty value # Print nonexistant keys as having empty value
if value is None: if value is None:
value = "" value = ""
printf("%s=%s\n", key, value) printf("%s=%s\n",
nilmdb.utils.unicode.encode(key),
nilmdb.utils.unicode.encode(value))

View File

@@ -5,6 +5,9 @@
#include <ctype.h> #include <ctype.h>
#include <stdint.h> #include <stdint.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
/* Values missing from stdint.h */ /* Values missing from stdint.h */
#define UINT8_MIN 0 #define UINT8_MIN 0
#define UINT16_MIN 0 #define UINT16_MIN 0
@@ -19,13 +22,6 @@
typedef int64_t timestamp_t; typedef int64_t timestamp_t;
/* This code probably needs to be double-checked for the case where
sizeof(long) != 8, so enforce that here with something that will
fail at build time. We assume that the python integer type can
hold an int64_t. */
const static char __long_ok[1 - 2*!(sizeof(int64_t) ==
sizeof(long int))] = { 0 };
/* Somewhat arbitrary, just so we can use fixed sizes for strings /* Somewhat arbitrary, just so we can use fixed sizes for strings
etc. */ etc. */
static const int MAX_LAYOUT_COUNT = 1024; static const int MAX_LAYOUT_COUNT = 1024;
@@ -58,7 +54,7 @@ static PyObject *raise_str(int line, int col, int code, const char *string)
static PyObject *raise_int(int line, int col, int code, int64_t num) static PyObject *raise_int(int line, int col, int code, int64_t num)
{ {
PyObject *o; PyObject *o;
o = Py_BuildValue("(iiil)", line, col, code, num); o = Py_BuildValue("(iiiL)", line, col, code, (long long)num);
if (o != NULL) { if (o != NULL) {
PyErr_SetObject(ParseError, o); PyErr_SetObject(ParseError, o);
Py_DECREF(o); Py_DECREF(o);
@@ -249,11 +245,11 @@ static PyObject *Rocket_get_file_size(Rocket *self)
/**** /****
* Append from string * Append from string
*/ */
static inline long int strtol10(const char *nptr, char **endptr) { static inline long int strtoll10(const char *nptr, char **endptr) {
return strtol(nptr, endptr, 10); return strtoll(nptr, endptr, 10);
} }
static inline long int strtoul10(const char *nptr, char **endptr) { static inline long int strtoull10(const char *nptr, char **endptr) {
return strtoul(nptr, endptr, 10); return strtoull(nptr, endptr, 10);
} }
/* .append_string(count, data, offset, linenum, start, end, last_timestamp) */ /* .append_string(count, data, offset, linenum, start, end, last_timestamp) */
@@ -264,6 +260,7 @@ static PyObject *Rocket_append_string(Rocket *self, PyObject *args)
int offset; int offset;
const char *linestart; const char *linestart;
int linenum; int linenum;
long long ll1, ll2, ll3;
timestamp_t start; timestamp_t start;
timestamp_t end; timestamp_t end;
timestamp_t last_timestamp; timestamp_t last_timestamp;
@@ -280,10 +277,13 @@ static PyObject *Rocket_append_string(Rocket *self, PyObject *args)
but we need the null termination for strto*. If we had but we need the null termination for strto*. If we had
strnto* that took a length, we could use t# and not require strnto* that took a length, we could use t# and not require
a copy. */ a copy. */
if (!PyArg_ParseTuple(args, "isiilll:append_string", &count, if (!PyArg_ParseTuple(args, "isiiLLL:append_string", &count,
&data, &offset, &linenum, &data, &offset, &linenum,
&start, &end, &last_timestamp)) &ll1, &ll2, &ll3))
return NULL; return NULL;
start = ll1;
end = ll2;
last_timestamp = ll3;
/* Skip spaces, but don't skip over a newline. */ /* Skip spaces, but don't skip over a newline. */
#define SKIP_BLANK(buf) do { \ #define SKIP_BLANK(buf) do { \
@@ -372,14 +372,14 @@ static PyObject *Rocket_append_string(Rocket *self, PyObject *args)
goto extra_data_on_line; \ goto extra_data_on_line; \
break break
CS(INT8, strtol10, t64.i, t8.i, t8.u, , 1); CS(INT8, strtoll10, t64.i, t8.i, t8.u, , 1);
CS(UINT8, strtoul10, t64.u, t8.u, t8.u, , 1); CS(UINT8, strtoull10, t64.u, t8.u, t8.u, , 1);
CS(INT16, strtol10, t64.i, t16.i, t16.u, le16toh, 2); CS(INT16, strtoll10, t64.i, t16.i, t16.u, le16toh, 2);
CS(UINT16, strtoul10, t64.u, t16.u, t16.u, le16toh, 2); CS(UINT16, strtoull10, t64.u, t16.u, t16.u, le16toh, 2);
CS(INT32, strtol10, t64.i, t32.i, t32.u, le32toh, 4); CS(INT32, strtoll10, t64.i, t32.i, t32.u, le32toh, 4);
CS(UINT32, strtoul10, t64.u, t32.u, t32.u, le32toh, 4); CS(UINT32, strtoull10, t64.u, t32.u, t32.u, le32toh, 4);
CS(INT64, strtol10, t64.i, t64.i, t64.u, le64toh, 8); CS(INT64, strtoll10, t64.i, t64.i, t64.u, le64toh, 8);
CS(UINT64, strtoul10, t64.u, t64.u, t64.u, le64toh, 8); CS(UINT64, strtoull10, t64.u, t64.u, t64.u, le64toh, 8);
CS(FLOAT32, strtod, t64.d, t32.f, t32.u, le32toh, 4); CS(FLOAT32, strtod, t64.d, t32.f, t32.u, le32toh, 4);
CS(FLOAT64, strtod, t64.d, t64.d, t64.u, le64toh, 8); CS(FLOAT64, strtod, t64.d, t64.d, t64.u, le64toh, 8);
#undef CS #undef CS
@@ -397,7 +397,8 @@ static PyObject *Rocket_append_string(Rocket *self, PyObject *args)
/* Build return value and return */ /* Build return value and return */
offset = buf - data; offset = buf - data;
PyObject *o; PyObject *o;
o = Py_BuildValue("(iili)", written, offset, last_timestamp, linenum); o = Py_BuildValue("(iiLi)", written, offset,
(long long)last_timestamp, linenum);
return o; return o;
err: err:
PyErr_SetFromErrno(PyExc_OSError); PyErr_SetFromErrno(PyExc_OSError);
@@ -431,14 +432,18 @@ static PyObject *Rocket_append_binary(Rocket *self, PyObject *args)
int data_len; int data_len;
int linenum; int linenum;
int offset; int offset;
long long ll1, ll2, ll3;
timestamp_t start; timestamp_t start;
timestamp_t end; timestamp_t end;
timestamp_t last_timestamp; timestamp_t last_timestamp;
if (!PyArg_ParseTuple(args, "it#iilll:append_binary", if (!PyArg_ParseTuple(args, "it#iiLLL:append_binary",
&count, &data, &data_len, &offset, &count, &data, &data_len, &offset,
&linenum, &start, &end, &last_timestamp)) &linenum, &ll1, &ll2, &ll3))
return NULL; return NULL;
start = ll1;
end = ll2;
last_timestamp = ll3;
/* Advance to offset */ /* Advance to offset */
if (offset > data_len) if (offset > data_len)
@@ -476,8 +481,8 @@ static PyObject *Rocket_append_binary(Rocket *self, PyObject *args)
/* Build return value and return */ /* Build return value and return */
PyObject *o; PyObject *o;
o = Py_BuildValue("(iili)", rows, offset + rows * self->binary_size, o = Py_BuildValue("(iiLi)", rows, offset + rows * self->binary_size,
last_timestamp, linenum); (long long)last_timestamp, linenum);
return o; return o;
} }
@@ -534,7 +539,7 @@ static PyObject *Rocket_extract_string(Rocket *self, PyObject *args)
if (fread(&t64.u, 8, 1, self->file) != 1) if (fread(&t64.u, 8, 1, self->file) != 1)
goto err; goto err;
t64.u = le64toh(t64.u); t64.u = le64toh(t64.u);
ret = sprintf(&str[len], "%ld", t64.i); ret = sprintf(&str[len], "%" PRId64, t64.i);
if (ret <= 0) if (ret <= 0)
goto err; goto err;
len += ret; len += ret;
@@ -556,14 +561,14 @@ static PyObject *Rocket_extract_string(Rocket *self, PyObject *args)
len += ret; \ len += ret; \
} \ } \
break break
CASE(INT8, "%hhd", t8.i, t8.u, , 1); CASE(INT8, "%" PRId8, t8.i, t8.u, , 1);
CASE(UINT8, "%hhu", t8.u, t8.u, , 1); CASE(UINT8, "%" PRIu8, t8.u, t8.u, , 1);
CASE(INT16, "%hd", t16.i, t16.u, le16toh, 2); CASE(INT16, "%" PRId16, t16.i, t16.u, le16toh, 2);
CASE(UINT16, "%hu", t16.u, t16.u, le16toh, 2); CASE(UINT16, "%" PRIu16, t16.u, t16.u, le16toh, 2);
CASE(INT32, "%d", t32.i, t32.u, le32toh, 4); CASE(INT32, "%" PRId32, t32.i, t32.u, le32toh, 4);
CASE(UINT32, "%u", t32.u, t32.u, le32toh, 4); CASE(UINT32, "%" PRIu32, t32.u, t32.u, le32toh, 4);
CASE(INT64, "%ld", t64.i, t64.u, le64toh, 8); CASE(INT64, "%" PRId64, t64.i, t64.u, le64toh, 8);
CASE(UINT64, "%lu", t64.u, t64.u, le64toh, 8); CASE(UINT64, "%" PRIu64, t64.u, t64.u, le64toh, 8);
/* These next two are a bit debatable. floats /* These next two are a bit debatable. floats
are 6-9 significant figures, so we print 7. are 6-9 significant figures, so we print 7.
Doubles are 15-19, so we print 17. This is Doubles are 15-19, so we print 17. This is
@@ -653,7 +658,7 @@ static PyObject *Rocket_extract_timestamp(Rocket *self, PyObject *args)
/* Convert and return */ /* Convert and return */
t64.u = le64toh(t64.u); t64.u = le64toh(t64.u);
return Py_BuildValue("l", t64.i); return Py_BuildValue("L", (long long)t64.i);
} }
/**** /****

View File

@@ -14,3 +14,4 @@ import nilmdb.utils.iterator
import nilmdb.utils.interval import nilmdb.utils.interval
import nilmdb.utils.lock import nilmdb.utils.lock
import nilmdb.utils.sort import nilmdb.utils.sort
import nilmdb.utils.unicode

22
nilmdb/utils/unicode.py Normal file
View File

@@ -0,0 +1,22 @@
def encode(u):
"""Try to encode something from Unicode to a string using the
default encoding. If it fails, try encoding as UTF-8."""
if not isinstance(u, unicode):
return u
try:
return u.encode()
except UnicodeEncodeError:
return u.encode("utf-8")
def decode(s):
"""Try to decode someting from string to Unicode using the
default encoding. If it fails, try decoding as UTF-8."""
if isinstance(s, unicode):
return s
try:
return s.decode()
except UnicodeDecodeError:
try:
return s.decode("utf-8")
except UnicodeDecodeError:
return s # best we can do

View File

@@ -88,7 +88,7 @@ class TestCmdline(object):
sys.exit(0) sys.exit(0)
except SystemExit as e: except SystemExit as e:
exitcode = e.code exitcode = e.code
captured = outfile.getvalue() captured = nilmdb.utils.unicode.decode(outfile.getvalue())
self.captured = captured self.captured = captured
self.exitcode = exitcode self.exitcode = exitcode