Hi I’m trying to utilize document tags to store some data, and having a hard time with it.
Heres what I’m doing:
Create an empty document tag.
in scripting, create a dictionary, that will be a list of dictionaries.
write that structure to the tag
then I want to append additional entries to the list, which I get an error.
#get the tag value
tagData = system.tag.readBlocking([myDocTag])[0].value
#create an instance of data i want to store
instance = {'stuff':'stuff info'}
#if the tag is empty, create the data structure
if tagData is None:
data = {'toplevel' : [instance]}
#the structure should exist, so just add to it
else:
tagData = dict(tagData)
tagData['toplevel'].append(instance) #I get an error here
#can't convert to com.inductiveautomation.ignition.common.document.DocumentElement
data = system.util.jsonEncode(tagData)
system.tag.writeBlocking([myDocTag], [data])
Is there something I’m missing?
Well I think your first mistake is assuming the value you get from reading a document tag is a python dictionary.
You can convert it to a dictionary with something like this:
qv = system.tag.read("DocTest")
dict = system.util.jsonDecode(str(qv.value))
The next issue is that dictionaries don’t have an append
method…
1 Like
You can also use .toDict()
:
qv = system.tag.read("DocTest")
doctest_dict = qv.value.toDict()
Also, just a quick warning. If you store java.util.Date type values to these tags, they get converted to a string and you will need to loop through the dict to parse them back to a Date object if you want to use them as a Date object again (system.date.parse(val_to_parse, "E MMM dd HH:mm:ss z yyyy")
).
1 Like
Hrm, I do convert the value i get from a tag using
(after the else:)
tagData = dict(tagData)
I’ll try to use json decode like your example though.
I’m not trying to append to dict, i’m trying to append to a list thats the value of a key in dictionary. like this:
test = {'top': []}
test['top'].append(1)
test['top'].append(2)
test['top'].append(3)
print test
>>> {'top': [1, 2, 3]}
well after getting the tag value, I didnt realize I needed to force it to a string first. Thanks that helped!
@WillMT10’s toDict()
method is a little cleaner than forcing it to string and parsing it.
1 Like
so is
system.tag.readBlocking([myDocTag])[0].value.toDict()
different than
dict(system.tag.readBlocking([myDocTag])[0].value)
?
Yes, because toDict()
is something we implemented on the Python-friendly document type you get from reading that tag’s value. I don’t know how dict()
will behave when receiving that object.
oh ok that makes sense. sweet well i’ll try that, thanks!
Is this something recent, or did I completely miss it somewhere? Up til now I was importing and using the functions in TypeUtilities.
I didn’t know it was there either… but it looks like it has been since 2018.
1 Like
A word of caution based on my observations...
JSON at its top level is always a dictionary of key/value pairs but the Ignition document tag seems to accept objects with lists at the top level.
The object returned by reading the value of a document tag will have a PyDocumentObjectAdapter object for levels of the object that are dictionary (dict) equivalents.
The object returned by reading the value of a document tag will have a will have an array.array
object for levels of the document that are list equivalents.
Calling .toDict()
on a PyDocumentObjectAdapter object will return the object convert to a py dict
object with deeper level PyDocumentObjectAdapter
objects also converted to py dict
objects and with deeper level array.array
objects converted to py list
objects.
Calling .tolist()
on an array.array
object will return will return the object convert to a py list
object but DOES NOT convert deeper level PyDocumentObjectAdapter
and array.array
objects. You cannot assume some lower level isn't still a PyDocumentObjectAdapter
object or array.array
object. In that case you may need to recursively process the whole object
def sanitize(obj):
if hasattr(obj, "append"): # list like object
if hasattr(obj, "tolist"): # array.array object
obj = obj.tolist()
for i in range(len(obj)):
obj[i] = sanitize(obj[i])
return obj
elif hasattr(obj, "items"): # dict like object
if hasattr(obj, "toDict"): # PyDocumentObjectAdapter object
obj = obj.toDict()
# We should not need to process the deeper levels
# else:
# for k, v in obj.iteritems():
# obj[k] = sanitize(v)
return obj
else:
return obj
obj_in =[{"a": [1,2], "b": 3, "c": {"x":4}}, {"y":5}, 100]
system.tag.writeBlocking([tagPath], [obj_in])
obj_out = system.tag.readBlocking([tagPath])[0].value
results = sanitize(obj_in)
print results
results.append(300)
results[0]["a"].append(3)
results[0]["c"]["y"] = 5
print results
Therefore it would seem good practice to always have the top level of the object be a dictionary so you can just call .toDict()
on the whole thing.
4 Likes