# Iterate through all components programatically in Perspective?

**URL:** <https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938>\
**Category:** Ignition\
**Tags:** ignition80, perspective\
**Created:** [March 9, 2020, 7:39pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938 "2020-03-09T19:39:52Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [March 9, 2020, 7:39pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/1 "2020-03-09T19:39:52Z")

</div>

I was wondering if there's a way to iterate through all components on screen for a perspective view? I was trying to use getRootContainer and getChildren but it doesn't seem as straight forward as I thought/as it was for Vision. Any know how this is done?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [March 9, 2020, 8:20pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/2 "2020-03-09T20:20:50Z")

</div>

You’ll have to recurse down the `children`; eg:

```python
def recurse(component):
		return {child.name: recurse(child) for child in component.children}
	
system.perspective.print(recurse(self.view.rootContainer))

```

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [March 10, 2020, 12:07pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/3 "2020-03-10T12:07:44Z")

</div>

And that component in `recurse(component)` would or at least could be a container right? Love recursive solutions, they’re so recursive.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [March 10, 2020, 2:40pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/4 "2020-03-10T14:40:56Z")

</div>

Right, just start the function with whatever component you want to build your tree from.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 4, 2023, 2:35pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/5 "2023-12-04T14:35:14Z")

</div>

Been a while but related to this - I want to go through each component, and if it has a custom property called `outValue` I want to stuff that into a dictionary that is returned. Any idea how I could modify the above to do that?

The end goal - go through all my components, if it has an `outValue` custom property, put that in a dictionary like `{componentName: outValue}`.

I was able to do this in Vision like so -

```auto
def parseContainer(rc, recursive=False, dataDictionary=None):
	"""
	Creates a dictionary that is to be used in conjunction of named queries.
	Key values are the database column names, and the values are the database column values.
	Looks to root container and grabs any custom properties that have a "_out_" prefix, strips that off an uses remained as the key name.
	Iterates through all components and checks if there is an outValue. If so, the name of the component will be used as the key value,
	and value of outValue as the value.
	Args:
		rc: root container of the window.
		recursive: bool, if True, runs this same thing on any child containers down
		dataDictionary: dictionary, key/values are added to this used in the case of recursive (though guess a coder could prepopultae a dictionary with other stuff
		and feed it in if they so chose to but no real reason to)
	Returns:
		dictionary {"column_name_1":column_value_1, "columne_name_2":column_value_2, ...}
	"""
	if dataDictionary is None:
		dataDictionary = {}
	for component in rc.components:
		# Recursive step for inner containers
		if isinstance(component, com.inductiveautomation.factorypmi.application.components.BasicContainer) and recursive:
			parseContainer(component, dataDictionary=dataDictionary)
		for prop in component.getProperties():
			if str(prop.getName()) == 'outValue':
				dataDictionary[component.getName()] = prop.getValue()		
	return dataDictionary

```

But the structure of these perspective components and view I am having trouble making this work. Any assistance would be greatly appreciated.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 4, 2023, 2:49pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/6 "2023-12-04T14:49:20Z")

</div>

Perspective doesn't expose any of its ~~hierarchy~~ (or bindings). At best, you could reprocess the on-disk JSON of the view to identify what ~~components are present and the~~ properties thereof (cache that) and use that to explicitly obtain runtime values.

Perspective simply isn't as geek-friendly as Vision. 🤷‍♂️

Edit: Hmmm. No, Perspective does expose a view's `.rootContainer` component and components expose their `.children`, so you can recursively identify all components in a view. You should do some introspection to see if you can enumerate properties.

If you are only looking for one named property, consider just accessing it on everything, wrapped in a `try:`, and discarding any nulls.

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 4, 2023, 2:51pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/7 "2023-12-04T14:51:21Z")

</div>

Unfortunate but glad I have an answer. Thanks Phil.

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [December 4, 2023, 3:54pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/8 "2023-12-04T15:54:26Z")

</div>

```auto
	dataDictionary = {}
	def recurse(component):
		for child in component.children:
			for c in child.custom:
				if "outValue" in c:
					dataDictionary[c] = child.custom[c]
			recurse(child)
	recurse(self.view.rootContainer)	
	system.perspective.print(dataDictionary)

```

not sure if this is what you were looking for?

---

<div class="post-metadata">

**Author:** ![bkarabinchak.psi](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bkarabinchak.psi/32/83567_2.png) [@bkarabinchak.psi](https://forum.inductiveautomation.com/u/bkarabinchak.psi)\
**Post date:** [December 4, 2023, 4:03pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/9 "2023-12-04T16:03:59Z")

</div>

Will be testing it soon, I think I just want this line to be `dataDictionary[child.name] = child.custom[c]` but otherwise I think this is what I am looking for. I want the component name (as those line up directly to columns in my named query) as my keys.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [December 4, 2023, 4:10pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/10 "2023-12-04T16:10:20Z")

</div>

You can write a simple recursive generator function that can be combined with other functional operations pretty easily:

```python
def getComponents(element):
	def walkComponents(component):
		for child in component.children:
			yield child
			walkComponents(child)
	
	return walkComponents(element)

hasOutProperty = lambda element: "outValue" in element.custom

parameters = {}
for component in filter(hasOutProperty, getComponents(self.view.rootContainer)):
	parameters[component.name] = component.custom["outValue"]

# or, for fun:
parameters = {
	c.name: c.custom["outValue"]
	for c in filter(hasOutProperty, getComponents(self.view.rootContainer))
}

```

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 4, 2023, 4:23pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/11 "2023-12-04T16:23:50Z")

</div>

> [@paul-griffith](#):
>
> `filter(getComponents(self.view.rootContainer), hasOutProperty)`

The filter function goes first

edit: I'm not sure what to call the filtering function actually

---

<div class="post-metadata">

**Author:** ![Carly\_Jankowski](https://avatars.discourse-cdn.com/v4/letter/c/e480ec/32.png) [@Carly\_Jankowski](https://forum.inductiveautomation.com/u/Carly_Jankowski)\
**Post date:** [December 4, 2023, 4:24pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/12 "2023-12-04T16:24:27Z")

</div>

How can I put this into a project library script so that I can call it on any container?

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 4, 2023, 4:27pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/13 "2023-12-04T16:27:03Z")

</div>

Put the `getComponents` function in your lib, let's say you put it in `lib/utils`, then you can call `lib.utils.getComponents(your_component)`

note that `lib` here is just a folder (package) named "lib", and `utils` is a script.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [December 4, 2023, 4:29pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/14 "2023-12-04T16:29:31Z")

</div>

same goes for the lambda function.

`lib.utils.hasOutProperty`

Although might make more since to do something like:

```auto
def hasProperty(element, property):
    return lambda element: property in element.custom

```

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 4, 2023, 4:32pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/15 "2023-12-04T16:32:24Z")

</div>

If you make it a function, you need to get rid of the lambda:

```python
def hasProperty(element, property):
    return property in element.custom

```

otherwise you're returning the lambda. Which is okay, if you actually pass a CALL to `hasProperty()`, and not `hasProperty` itself. But that's a weird thing to do.

edit: actually, a function like this won't work with `filter`, it's only expecting one parameter.  
You can get around that with tuples, or calling a function in a lambda, but... Things are getting weird.  
Just use a lambda like Paul did. That's what they're for.

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [December 4, 2023, 4:42pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/16 "2023-12-04T16:42:46Z")

</div>

> [@pascal.fragnoud](#):
>
> Just use a lambda like Paul did. That's what they're for.

Yes, that lambda if fine, and perhaps in @bkarabinchak.psi's case works great, but it requires the property be named exclusively `'outValue'` or whatever property you type in. In most cases you would want it to be more generic so you can pass in the property that you are using.

hmmm, I'll need to mess around with this.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [December 4, 2023, 4:44pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/17 "2023-12-04T16:44:21Z")

</div>

`functools.partial` is the solution:

```python
from functools import partial

def hasProperty(element, property, scope = 'custom'):
    return lambda element: property in element[scope]

parameters = {
	c.name: c.custom["outValue"]
	for c in filter(partial(hasProperty, property="outValue"), getComponents(self.view.rootContainer))
}

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [December 4, 2023, 4:45pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/18 "2023-12-04T16:45:47Z")

</div>

Or, of course, the less-meta-programmy, probably more Pythonic solution:

```auto
parameters = {
	c.name: c.custom["outValue"]
	for c in getComponents(self.view.rootContainer) if "outValue" in c.custom
}

```

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [December 4, 2023, 4:46pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/19 "2023-12-04T16:46:50Z")

</div>

Well lambdas are not meant to be generic.

You could define a generic function, and pass it your property name with `functools.partial`, or think of other convoluted ways of doing this... but in the end, this:

```python
filter(lambda el: 'foo' in el), some_iterator)

```

is the simplest and most pythonic way of doing it. At least with `filter`. Some will argue that

```python
[el for el in some_iterator if 'foo' in el]

```

is the way to go. To each his own.

edit:  
Hey, it seems I'm on the same wavelength as Paul on this !

---

<div class="post-metadata">

**Author:** ![Felipe\_CRM](https://avatars.discourse-cdn.com/v4/letter/f/dfb087/32.png) [@Felipe\_CRM](https://forum.inductiveautomation.com/u/Felipe_CRM)\
**Post date:** [December 4, 2023, 4:52pm UTC](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938/20 "2023-12-04T16:52:28Z")

</div>

You could also use currying probably:

```auto
elementhasproperty = lambda property: lambda element: property in element.custom

... filter(elementhasproperty("outvalue"), getComponents(self.view.rootContainer)) ...

```

Tested in script console:

```auto
>>> xiny = lambda x: lambda y: x in y
>>> abiny = xiny("ab")
>>> abiny("B")
False
>>> abiny("abstract")
True
>>> fooiny = xiny("foo")
>>> fooiny("abstract")
False
>>> fooiny("football")
True
>>> xiny("baz")("foobazbar")
True
>>> filter(xiny("foo"), ["football", "baseball", "foolish", "wise"])
['football', 'foolish']

```

Edit: fixed typo, actual test case with `filter`

[Next page](https://forum.inductiveautomation.com/t/iterate-through-all-components-programatically-in-perspective/32938.md?page=2)
