Cython: DMS: JSON formatted comments and history handling

This commit is contained in:
Celine Mercier
2018-10-07 19:06:59 +02:00
parent 74be3c39f0
commit 35cf2962cc
3 changed files with 166 additions and 3 deletions

View File

@ -4,16 +4,30 @@ from .obitypes cimport const_char_p, \
obiversion_t
cdef extern from "obidms.h" nogil:
struct OBIDMS_infos_t :
bint little_endian
size_t file_size
size_t used_size
const_char_p comments
ctypedef OBIDMS_infos_t* OBIDMS_infos_p
struct OBIDMS_t:
const_char_p dms_name
const_char_p dms_name
OBIDMS_infos_p infos
ctypedef OBIDMS_t* OBIDMS_p
OBIDMS_p obi_dms(const_char_p dms_name)
OBIDMS_p obi_open_dms(const_char_p dms_path)
OBIDMS_p obi_test_open_dms(const_char_p dms_path)
OBIDMS_p obi_create_dms(const_char_p dms_path)
int obi_dms_exists(const char* dms_path)
int obi_dms_write_comments(OBIDMS_p dms, const char* comments)
int obi_dms_add_comment(OBIDMS_p dms, const char* key, const char* value)
int obi_close_dms(OBIDMS_p dms, bint force)
char* obi_dms_get_dms_path(OBIDMS_p dms)
char* obi_dms_get_full_path(OBIDMS_p dms, const_char_p path_name)

View File

@ -9,3 +9,7 @@ cdef class DMS(OBIWrapper):
cdef inline OBIDMS_p pointer(self)
cpdef int view_count(self)
cdef class DMS_comments(dict):
cdef DMS _dms

View File

@ -9,14 +9,18 @@ from .capi.obidms cimport obi_open_dms, \
obi_close_dms, \
obi_dms_exists, \
obi_dms_get_full_path, \
obi_close_atexit
obi_close_atexit, \
obi_dms_write_comments
from .capi.obitypes cimport const_char_p
from obitools3.utils cimport bytes2str, \
str2bytes, \
tobytes, \
tostr
tostr, \
bytes2str_object, \
str2bytes_object, \
clean_empty_values_from_object
from .object cimport OBIDeactivatedInstanceError
@ -25,6 +29,9 @@ from pathlib import Path
from .view import view
from .object import OBIWrapper
import json
import time
cdef class DMS(OBIWrapper):
@ -107,6 +114,21 @@ cdef class DMS(OBIWrapper):
return <bytes> self.pointer().dms_name
# command history DOT graph property getter in the form of a bytes string
@property
def dot_history_graph(self):
complete_graph = []
for view_name in self:
complete_graph.extend(self[view_name].dot_history_graph_list)
uniq_graph = []
for elt in complete_graph:
if elt not in uniq_graph:
uniq_graph.append(elt)
uniq_graph.insert(0, b"digraph \""+self.name+b"\" {\n")
uniq_graph.append(b"}")
return b"".join(uniq_graph)
@OBIWrapper.checkIsActive
def keys(self) :
@ -181,6 +203,129 @@ cdef class DMS(OBIWrapper):
for view_name in self.keys():
s = s + repr(self.get_view(view_name)) + "\n"
return s
@OBIWrapper.checkIsActive
def record_command_line(self, command_line):
t = time.asctime(time.localtime(time.time()))
if "command_line_history" not in self.comments:
l = []
else:
l = self.comments["command_line_history"]
l.append({"command":command_line, "time":t})
self.comments["command_line_history"] = l
# comments property getter
@property
def comments(self):
return DMS_comments(self)
@comments.setter
def comments(self, object value):
DMS_comments(self, value)
# bash command history property getter
@property
def bash_history(self):
s = b"#!/bin/bash\n\n"
first = True
for command in self.command_line_history:
s+=b"#"
s+=command[b"time"]
s+=b"\n"
s+=command[b"command"]
s+=b"\n"
return s
# command line history property getter
@property
def command_line_history(self):
return self.comments[b"command_line_history"]
cdef class DMS_comments(dict): # Not thread safe
def __init__(self, DMS dms, value=None) :
if not dms.active() :
raise OBIDeactivatedInstanceError()
self._dms = dms
if value is not None:
self.update(value) # TODO test and discuss not overwriting (could use replace bool)
self._update_from_file()
def _update_from_file(self):
cdef bytes comments_json
cdef str comments_json_str
cdef OBIDMS_p dms_p
cdef DMS dms
if not self._dms.active() :
raise OBIDeactivatedInstanceError()
dms = self._dms
dms_p = <OBIDMS_p>(dms.pointer())
comments_json = <bytes> dms_p.infos.comments
comments_json_str = bytes2str(comments_json)
comments_dict = json.loads(comments_json_str)
str2bytes_object(comments_dict)
super(DMS_comments, self).update(comments_dict)
def __getitem__(self, object key):
if not self._dms.active() :
raise OBIDeactivatedInstanceError()
if type(key) == str:
key = str2bytes(key)
self._update_from_file()
return super(DMS_comments, self).__getitem__(key)
def __setitem__(self, object key, object value):
cdef OBIDMS_p dms_p
cdef DMS dms
if not self._dms.active() :
raise OBIDeactivatedInstanceError()
dms = self._dms
dms_p = <OBIDMS_p>(dms.pointer())
# Remove virtually empty values from the object # TODO discuss
clean_empty_values_from_object(value)
# If value is virtually empty, don't add it # TODO discuss
if value is None or len(value) == 0:
return
# Convert to bytes
if type(key) == str:
key = str2bytes(key)
value_bytes = str2bytes_object(value)
# Update dict with comments already written in file
self._update_from_file()
# Add new element # TODO don't overwrite?
super(DMS_comments, self).__setitem__(key, value_bytes)
# Convert to str because json library doens't like bytes
dict_str = {key:item for key,item in self.items()}
dict_str = bytes2str_object(dict_str)
# Convert to json string
comments_json = json.dumps(dict_str)
# Write new comments
if obi_dms_write_comments(dms_p, tobytes(comments_json)) < 0:
raise Exception("Could not write DMS comments, DMS:", dms.name, "comments:", comments_json)
def update(self, value):
for k,v in value.items():
self[k] = v
def __contains__(self, key):
return super(DMS_comments, self).__contains__(tobytes(key))
def __str__(self):
return bytes2str(self._dms.pointer().infos.comments)