Perspective properties export/import to/from database

Anyone knows how to get the json from the props tree of a view by scripting?

If i right click and click “Copy”, then paste into a text editor. I get the JSON properly. But how can I do this with a script?

Further, given that i have the JSON stored in a DB, any tips on how to replace the exisitng view props?

EDIT: Save yourself from some unnecessary reading and see my next response in this thread. The only thing worth noting in this post is the first block of code for serialization.

I had similar questions. As of a forum post from August, it seems they’re still working on being able to cast Perspective properties as python objects. The short of it is that you can import JSON objects as the properties, and there’s not an easy way (as far as I know) to retrieve the properties in a JSON format.

My workaround until that’s available is to re-create the property you’re trying to save as a python dictionary, do a json.dumps on that python object, then put it into the database (I’ve also been serializing my json dump strings for easier storage as byte arrays rather than trying to store potentially huge VARCHARs). Then, when you want to load it, do a json.loads on the data from your query. You can then directly set the property you loaded to the now-decoded JSON object.

Here’s code for serialization/deserialization:

# I named this file serialization, you can call it whatever
import java.io
import collections

# serializes a given object into a byte array, 
# usually to store in the database to retrieve later.
def serialize(object):
	baos = java.io.ByteArrayOutputStream()
	oos = java.io.ObjectOutputStream(baos)
	oos.writeObject(object)
	oos.close()
	return baos.toByteArray()

# deserializes a byte array object.
def deserialize(object):
	bais = java.io.ByteArrayInputStream(object)
	ois = java.io.ObjectInputStream(bais)
	return ois.readObject()

And here’s a simplified example:

import json

# create a dict matching the prop you want 
# to save, say, a style property.
# It's usually pretty trivial to recreate the structure of
# the property from within one of the parent object's events--
# I usually do loading and saving within onStartup and 
# onShutdown event scripts for example
my_prop = {"classes": "Menu Bold_Text", "backgroundColor" : "#DADDE0"}

# make a JSON string
prop_json_data = json.dumps(my_prop)

# (optional) serialize data for easier storage
serialized_data = serialization.serialize(prop_json_data)

# (From here, you would run an update query to store either 
# the JSON string or serialized string into your database)

# Then, to retrieve the object, run your retrieval 
# query and get the object(s) from your dataset 
# (best done in try/catch/finally in a transaction, 
# I'm just being lazy in this example here)
query_results = system.db.runNamedQuery(...) 

# (deserialize if you serialized)
json_string = serialization.deserialize(query_results.getValueAt(0,0) )

# load the string so we get the JSON object back
retrieved_prop = json.loads(json_string)

# finally, simply set the property to the retrieved property
self.props.style = retrieved_prop

Kind of a rough outline, but I hope this helps. There might even be a better way to do it, but this is what I’ve been doing since early release without any issues.

2 Likes

This is great. Specifically the serialize functions!

I will probably use all of your code when the prop dump is available by some means…

Guess we will just have to wait untill the props can be retrieved into JSON.

Great news!

Although, as far as I could tell, this is completely undocumented, it nonetheless works for pulling out properties as JSON objects without the need for re-creating them from scratch:

from com.inductiveautomation.ignition.common import TypeUtilities
jsonObj = TypeUtilities.pyToGson(self.props.labels) # (or w/e your prop is)

EDIT: pyToJson --> pyToGson as of Ignition release version 8.0.5. Thanks, @PGriffith!

From here, you can serialize the jsonObject for storage and deserialize as needed. This obviates the need for importing Python’s json module.

For completeness’s sake, here’s an updated example (without copying the previous serialization code, since that’s the same):

from com.inductiveautomation.ignition.common import TypeUtilities

# Grab the property you want to save as a JSON object
jsonObj = TypeUtilities.pyToGson(self.props.style)

# (optional) serialize data for easier storage
serializedJson = serialization.serialize(jsonObj)

# (From here, you would run an update query to store either 
# the raw JSON string or serialized string into your database)

# Then, to retrieve the object, run your retrieval 
# query and get the object(s) from your dataset 
# (best done in try/except/finally block)
queryResults = system.db.runNamedQuery(...) 

# deserialize to get the json object back
retrievedJsonObj = serialization.deserialize(queryResults.getValueAt(0,0) )

# finally, simply set the property to the retrieved property
self.props.style = retrievedJsonObj

Credit to @grietveld for his solution on the post here. Huge timesaver! I only wish it was documented somewhere. I scoured docs for TypeUtilities and found nothing, which makes me wonder where this module was found…lol.

4 Likes

Note that it should be pyToGson, not pyToJson. TypeUtilities is an internal class, although it powers a few functions (including, ironically, the insufficient-for-this-use-case system.util.jsonEncode()). I just talked to another developer today, and we’re considering adding a new system.json namespace or some other, supercharged replacement for system.util.jsonEncode/decode.

2 Likes

When I use “pyToGson” I get an AttributeError saying the function doesn’t exist:

AttributeError: type object 'com.inductiveautomation.ignition.common.TypeUtilit' has no attribute 'pyToGson'

Looks like it’s shortening ‘TypeUtilities’ to ‘TypeUtilit’ for some reason?
When I substitute “pyToJson” into the exact same code, the error goes away and the code behaves as desired.

More info:

I’m on Ignition 8.0.5.
I was able to reproduce the result in two different projects by creating a new view, adding a component (I tried with both a pie chart and icon), and placing the following code onto any event (I used onClick and onContextMenu events):

	from com.inductiveautomation.ignition.common import TypeUtilities
	jsonObj = TypeUtilities.pyToGson(self.props.style) # pyToJson works here?!
	system.perspective.print(jsonObj)

I’m going to leave my post as is with ‘pyToJson’ for the time being since it works in my use case; thank you for the heads up, though!

That’s incredibly strange. The code has pyToGson() in 8.0.5 and future versions, and has never had pyToJson() that I can see. Be aware that you may need to update your scripts at some point if that issue ever resolves. Did you install a nightly build of 8.0.5 or 8.0.6 at some point?

That’s incredibly strange.

You're telling me! Haha.

Did you install a nightly build of 8.0.5 or 8.0.6 at some point?

As far as I know, we're on an 8.0.5 nightly build on our projects, which I believe explains the oddity...I'll go ahead and fix my post. Thanks for helping me get to the bottom of that (and have a good turkey day)!

1 Like