Copy Object Details by Value, Not Reference

Good Morning. I’m working Perspective on the 8.0.16 Gateway. I have a script that is copying the props.elements of an SVG to use elsewhere in the project. When I update my copy of the data, it is also changing the original object’s data, since I’m actually given a reference to the original object, not a copy of the object. How can I go about copying the data without simply receiving a reference to the original object?

#Get the element data from the original object
element_adjusted = self.getSibling('test_2').props.elements[0]

#Update the information for the new object (also updates the original object)
element_adjusted.transform = 'translate(50,0) scale (1.0)'

#Write the adjusted data to the new object
elements_list.append(element_adjusted) 
self.getSibling('aggregate_layout').props.elements = elements_list

Thanks in advance!

Not much time for to dig in here, but would this work?
element_adjusted = self.getSibling('test_2').props.elements[0].copy()

1 Like

FYI many objects in igntion have a .copy() function that can be used, always worth checking that out first.

Generally speaking, see what functions and properties are available on a given object,

x = some.ignition.object.thing
for option in dir(x):
    print option

will give you a list of properties and callable functions on said object - if copy is in that list, you can use .copy().

Thanks for the quick responses guys. There is no copy function for this object, but there is a __copy__ - not sure what that means.

Trying copy()

component_copy = self.getSibling('test_2').copy()

elements_list = []
elements_list.append(component_copy.props.elements[0]) 
self.getSibling('aggregate_layout').props.elements = elements_list 

Created this error —

Error running action 'component.onActionPerformed' on 
pages/system/overview@C$0:1:0:2/root/coord_overview/Button: 
Traceback (most recent call last): File "<function:runAction>", line 7, in
 runAction AttributeError: 'com.inductiveautomation.perspective.gateway.script' 
object has no attribute 'copy'

Trying __copy__

component_copy = self.getSibling('test_2').__copy__

elements_list = []
elements_list.append(component_copy.props.elements[0]) 
self.getSibling('aggregate_layout').props.elements = elements_list 

Created this error —

Error running action 'component.onActionPerformed' on 
pages/system/overview@C$0:1:0:2/root/coord_overview/Button: 
Traceback (most recent call last): File "<function:runAction>", line 10, 
in runAction AttributeError: 'builtin_function_or_method' object has no attribute 'props'

It’s interesting this one seemed to work (didn’t error out), but returned a ‘builtin_function_or_method’ object.

Ok, let’s try this:

import copy

component_copy = copy.copy(self.getSibling('test_2')) # shallow copy
# -or-
component_copy = copy.deepcopy(self.getSibling('test_2')) # deep copy

copy.copy(self.getSibling('test_2')) returns this error:

image

copy.deep_copy(self.getSibling('test_2')) returns this error:

image

Ever used monkey patching as recommended in the error message? Don’t want to take the time to learn how to use it to find out that it’s not what I need.

Worst case, I’m looking at simply reading through the elements’ JSON and recreating a copy line-by-line. Definitely not the quickest way.

What if you put the property you were trying to copy, instead of the entire component?
element_adjusted = copy(self.getSibling('test_2').props.elements[0])

I had that same thought earlier, but had no dice. Calling either

copy(self.getSibling('test_2').props.elements[0])

or

copy(self.getSibling('test_2').props.elements)

both give error

What component are you working with? I’ll take a closer look when time allows.

I’m using the Drawing component, created by dragging an SVG image into the Designer and selecting to Embed it. Screenshot of the object properties and the JSON of the elements are attached.

[
  {
    "type": "group",
    "elements": [
      {
        "type": "path",
        "fill": {
          "paint": "#E03DBD"
        },
        "style": {},
        "d": "M 0,0 50,0 50,20 0,20",
        "name": "path_01"
      }
    ],
    "name": "layer1",
    "transform": "translate(0,0) scale(1.0)"
  }
]

You can do a recursive descent function, converting to builtin types each step of the way, like this:

1 Like

The sanitize_tree function snippet did the trick for me. Thanks for the help, gentlemen.