Is there a function out there that will turn a json string or python dict into ObjectWrapper?
If I take a python dict and assign it to a property on a perspective view it turn the property into a object. It I then go and get the property in script the property does not come back as a dictionary it comes back as an ObjectWrapper. What I want to do in script is go from a dictionary to an object wrapper without having to assing it to a view property.
We have objects that we serialized and stored on the views. Then later when we need that object we can deserialize the ObjectWrapper.
The problem now is I want to store the serialized object in a string tag, but when I pull it back out and try the existing deserializing it does not work because I cannot reference the string like the ObjectWrapper. I also tried using system.util.jsonDecode(), but that turns it into a dictionary and I cannot reference the properties the same way
If you had a function to turn an ObjectWrapper into a python dictionary I could probably make that work with out to much refactoring on our side.
I would then have to change all our deserialize functions to reference properties like this
You should be able to dict(<objectWrapper>) within a release or two; I opened a PR for that last week, just needs QA sign off. That’s probably going to be the sanest way forward; you most likely won’t have any success trying to manually convert an object into one of the wrapper types.
I’d also highly recommend migrating towards the __getitem__/braces syntax, over attribute retrieval. We make that work to make things nicer for anyone more used to working with JS objects, but it’s got limitations from a Pythonic perspective.
I’m trying to do this as well. I have a custom param that’s an Object with this format:
When I use dict() to convert to a dict, the base controlAccess works fine, but its key values are still ObjectWrappers. I assume i’m going to have to loop through it and convert all ObjectWrappers into dicts?
I’ve just tried this and I can’t import the object: import com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper
With the error: ImportError: No module named perspective
This works, but yuck! str(type(dict(self.view.custom.controlAccess)['racking'])) == "<type 'com.inductiveautomation.perspective.gateway.script.PropertyTreeScriptWrapper$ObjectWrapper'>"
Ah, so it is an ObjectWrapper…
Interesting. I’m actually not sure whether we can ‘fix’ that; it’d be nice if dict was automatically recursive, but c’est la vie. We’d have to introduce a new method, which sounds pretty gross…
You could make your deep to-dict function not care about specific types by relying on the presence of Python magic methods, as in this post:
Cool, that looks useful
What I’m trying to do is to make a copy of that controlAccess object, manipulate it, then write it back. What I found was that if I just assigned a variable to it e.g. controlAccess = self.custom.controlAccess, the controlAccess python variable became a reference to the View’s custom property, which I thought was a bit strange.
Is there a better way to do this, rather than converting things all to dicts? can I make a copy like dict’s copy() method of an ObjectWrapper object?
Well, dict.copy() is just a shallow copy - it’s basically doing exactly what dict(<some dict>) would do. A less performant, but maybe easier solution would be to json.loads(json.dumps(self.custom.controlAccess)) - that’ll be an easy deep-copy. (The same technique is common in the front-end world).
Forcing each to the expected type while traversing makes a deep copy:
if hasattr(element, '__iter__'):
if hasattr(element, 'keys'):
return dict((k, sanitize_tree(element[k])) for k in element.keys())
return list(sanitize_tree(x) for x in element)
EDIT: Got rid of the unnecessary zip() and used only one keys() iterator instead of two.