# Table of Part Numbers with attributed run rate (PPM)

**URL:** <https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684>\
**Category:** Ignition\
**Tags:** ignition80\
**Created:** [April 21, 2022, 1:01pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684 "2022-04-21T13:01:41Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 1:01pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/1 "2022-04-21T13:01:41Z")

</div>

Hey everyone,

I am completely new to this environment but have already enjoyed the features I have utilized so far. However, I ran into an issue. I am attempting to script a property change event that executes when the user changes the PPM/run rate of the machine. This run rate is also to update a Power table where the part numbers and their attributed PPM’s are stored, but does not update the table, only the UPC. I get an error as follows:  
Error executing script for event: `propertyChange`  
on component: `Run Rate`  
Details:  
File “event:propertyChange”, line 3, in   
AttributeError: ‘NoneType’ object has no attribute ‘replace’

The script in the numeric text field:

```auto
if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number")
	ATMSettings.setRunRateFromPartNumber(int(partNumber.replace(",","")), int(event.newValue))

```

I also want to point out that in the tree, the ‘Run Rate’ is in Templates-\> Data-\> Run Rate. and the power table is under Windows-\> Standard Run Rates-\> Root Container-\> Power Table SRR.

Thanks for looking at my issue if you have a second!

---

<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:** [April 21, 2022, 1:12pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/3 "2022-04-21T13:12:47Z")

</div>

partNumber references a component directly.

So partNumber.replace() doesn’t exist - I assuming an you are trying to do this to a get rid of commas out of an integer string? This is unnecessary if you grab the `.intValue` from the component directly.

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 1:22pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/4 "2022-04-21T13:22:04Z")

</div>

Here is the rest of the code that is within the project library

```auto

def getRunRateFromPartNumber(partNumber):
	settings = system.tag.readBlocking(["[default]Concentrator PLC/ATM_Settings"])
	settingsDataset = settings[0].value
	return datasetFindValue(settingsDataset, "PartNumber", partNumber, "RunRate")

def setRunRateFromPartNumber(partNumber, newRunRate):
	settings = system.tag.readBlocking(["[default]Concentrator PLC/ATM_Settings"])
	settingsDataset = settings[0].value
	newDataset = datasetFindReplace(settingsDataset, "PartNumber", partNumber, "RunRate", newRunRate)
	system.tag.writeBlocking(["[default]Concentrator PLC/ATM_Settings"], [newDataset])
	addHistoryEntry(partNumber, newRunRate)
	
def addHistoryEntry(partNumber, newRunRate):
	historyDataset = system.tag.readBlocking(["[default]Concentrator PLC/History"])[0].value
	newDataset = system.dataset.addRow(historyDataset, historyDataset.getRowCount(), [system.date.now(), partNumber, newRunRate, system.security.getUsername()])
	system.tag.writeBlocking(["[default]Concentrator PLC/History"], [newDataset])

def datasetFindValue(dataset, searchColName, searchValue, returnColName):
	for row in system.dataset.toPyDataSet(dataset):
		if row[searchColName] == searchValue:
			try:
				return row[returnColName]
			except:
				raise Exception("Column name doesn't exist: " + returnColName)
				return ""
	
	return ""
	
def datasetFindReplace(dataset, searchColName, searchValue, replaceColumn, replaceValue):
	rowCt = 0
	for row in system.dataset.toPyDataSet(dataset):
		if row[searchColName] == searchValue:
			return system.dataset.setValue(dataset, rowCt, replaceColumn, replaceValue)
		
		rowCt += 1
	
	raise Exception("Couldn't find column " + searchColName + " with value " + str(searchValue) + " in the dataset, returning original dataset")
	return dataset

```

---

<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:** [April 21, 2022, 1:24pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/5 "2022-04-21T13:24:13Z")

</div>

> [@Alex\_Henry](#):
>
> `partNumber = event.source.parent.getComponent("Part Number")`

Is this a text field? You probably want `partNumber = event.source.parent.getComponent("Part Number").text` if this is something you need to get an int out of.

Alternatively and probably better is to use a numeric text field, you can make your number masking to have commas (or not) and then you can grab `partNumber = event.source.parent.getComponent("Part Number").intValue` and not have to worry about manually getting rid of commas out of an integer.

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 1:31pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/6 "2022-04-21T13:31:45Z")

</div>

Thanks for the suggestion. You make a really good point and it was originally set up as a text field and I changed it to a numeric text field, and wasn’t aware I could remove the commas under this type of field. I made these changes and the script looks better but is still throwing a similar error.

File “event:propertyChange”, line 2, in   
AttributeError: ‘NoneType’ object has no attribute ‘intvalue’

In advance, sorry if I miss something I currently have the flu and am working 😆

---

<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:** [April 21, 2022, 1:40pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/7 "2022-04-21T13:40:28Z")

</div>

Think it should be `.intValue`, everything is camelCased in Ignition.

However, I don’t even trust myself to type component relationships correctly by hand - I just always use the property selector to find and pick what property I need.

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 1:43pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/8 "2022-04-21T13:43:53Z")

</div>

Oops, good catch. I corrected the notation but got the same error. Rookie mistake ha.

```auto
if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number").intValue
	ATMSettings.setRunRateFromPartNumber(int(partNumber.replace()), int(event.newValue))

```

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [April 21, 2022, 1:45pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/9 "2022-04-21T13:45:06Z")

</div>

Did you use the property selector? If not, delete what you have and use the property selector like @bkarabinchak.psi mentioned.

---

<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:** [April 21, 2022, 1:47pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/10 "2022-04-21T13:47:52Z")

</div>

Well now `partNumber` has `type` of `int` so it will not have a `.replace()` function, nor do you need to typecast it as it is already an int.

An AttributeError means you are calling a property or method on something that does not exist, and an integer does not have a `replace` method.

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 1:59pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/11 "2022-04-21T13:59:18Z")

</div>

I did and got a whole new error.  
Traceback (most recent call last):  
File “event:propertyChange”, line 2, in   
AttributeError: ‘NoneType’ object has no attribute ‘event’

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 2:00pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/12 "2022-04-21T14:00:21Z")

</div>

You’re making some great points. How would you structure it since I have literally chopped it to death and am clearly leaving behind unnecessary functions?

---

<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:** [April 21, 2022, 2:00pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/13 "2022-04-21T14:00:56Z")

</div>

I would think this is enough

```auto
if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number").intValue
	ATMSettings.setRunRateFromPartNumber(partNumber), int(event.newValue))

```

Though since you are looking for the propertyName `intValue`, the event.newValue\event.oldValue will be of `int` type, so you can probably do it as

```auto
if event.propertyName == "intValue":
	partNumber = event.source.parent.getComponent("Part Number").intValue
	ATMSettings.setRunRateFromPartNumber(partNumber), event.newValue)

```

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [April 21, 2022, 2:47pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/14 "2022-04-21T14:47:28Z")

</div>

Okay, I made the changes to remove anything not needed and I still get the ‘intValue’ in line 2. Could the issue be that because the ‘intValue’ I am trying to use is inside the power table and I am stuck in the Data under Templates. Do I need to drill out and then back down into the windows to use the correct property?

When I use the ‘Insert Property Reference’ I cannot get to the Part Number because it is in the Power Table under Windows.

---

<div class="post-metadata">

**Author:** ![Alex\_Henry](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/alex_henry/32/31657_2.png) [@Alex\_Henry](https://forum.inductiveautomation.com/u/Alex_Henry)\
**Post date:** [May 17, 2022, 8:00pm UTC](https://forum.inductiveautomation.com/t/table-of-part-numbers-with-attributed-run-rate-ppm/58684/15 "2022-05-17T20:00:28Z")

</div>

For anyone who may need this information in the future within the community, the solution to my issue was as follows:

```auto
if event.source.parent.txtPartNumber:
	partNumber = event.source.parent.txtPartNumber
	ATMSettings.setRunRateFromPartNumber(partNumber, event.newValue)

```

There were a few problems found throughout the troubleshooting, but after some cleaning up and pointing to the correct data “txtPartNumber”, the issue was resolved. Hopefully this will help someone else.
