Cython: DMS: JSON formatted comments and history handling
This commit is contained in:
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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) :
|
||||
|
||||
@ -183,4 +205,127 @@ cdef class DMS(OBIWrapper):
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user