# Python issue replacing an empty key

**URL:** <https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583>\
**Category:** General Discussion\
**Created:** [June 5, 2019, 4:46pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583 "2019-06-05T16:46:56Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![RForshey](https://avatars.discourse-cdn.com/v4/letter/r/dc4da7/32.png) [@RForshey](https://forum.inductiveautomation.com/u/RForshey)\
**Post date:** [June 5, 2019, 4:46pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/1 "2019-06-05T16:46:56Z")

</div>

Hello to all! Python novice here back with another problem… ☹

Here’s the script:

```auto
data = jsonDict['data'][0]
operDict = jsonDict['data'][0]['operations'] 
rows = []
FMT = '%Y-%m-%d %H:%M:%S' 
for row in operDict:
	newrow = []
	newrow.append(row['fwork-code'])
	newrow.append(row['fwork-id'])
	newrow.append(row['fwork-dscr'])
	newrow.append(row['from']) 
	newrow.append(row['to'])
	d1 = row['from']
	d2 = row['to']
	newrow.append(datetime.strptime(d2, FMT) - datetime.strptime(d1, FMT))
	newrow.append(round(row['actualtime']/3600.0,2))
	newrow.append(row['status'])
	rows.append([str(r) for r in newrow])

headers = ['OP Code', 'ID', 'Description', 'Start', 'End', 'Elapsed', 'Labor Hrs', 'Status']
dataset = system.dataset.toDataSet(headers, rows)
event.source.parent.getComponent('Oper_Table').data = dataset

```

It works perfectly, right up until it hits an empty “from” or “to”

I’ve tried ‘if else’, ‘try and except’, and just can’t get past the error. Here’s my try and except:

```auto

	newrow.append(row['fwork-dscr'])
	try:
		newrow.append(row['from']) 
	except:
		datetime.strptime(datetime.now(),FMT)
	try:
		newrow.append(row['to'])
	except:
		datetime.strptime(datetime.now(),FMT)

```

But I still get this error:

```auto
Traceback (most recent call last):
  File "<event:actionPerformed>", line 33, in <module>
  File "C:\Users\rforshey\.ignition\cache\gwhaycic_8088_443_main\C0\pylib\datetime.py", line 1499, in strptime
    return cls(*(_time.strptime(date_string, format))[0:6])
ValueError: time data did not match format: data= fmt=%Y-%m-%d %H:%M:%S

```

Any ideas from the Python experts out there?

Thanks!!

---

<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:** [June 5, 2019, 5:11pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/2 "2019-06-05T17:11:25Z")

</div>

A technique like this should work:

```auto
if row['from']: # row value is 'truthy', ie, not an empty string or null value (None)
	d1 = datetime.strptime(row['from'], FMT)
else:
	d1 = datetime.strptime(system.date.now(), FMT)
newrow.append(d1)

```

Although, that still won’t protect you from a value being present that _isn’t_ a valid datestring for your format specifier - to catch that, wrap it all in a `try/except`:

```auto
try:
	if row['from']: # row value is 'truthy', ie, not an empty string or null value (None)
		d1 = datetime.strptime(row['from'], FMT)
	else:
		d1 = datetime.strptime(system.date.now(), FMT)
except ValueError:
	d1 = "Invalid date"
newrow.append(d1)

```

Also, not a big deal, but if you’re posting code on the forums it’s best to put it inside triple backticks so formatting isn’t lost:

````
```
code

```
````

---

<div class="post-metadata">

**Author:** ![Stevenson.Yuan](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Stevenson.Yuan](https://forum.inductiveautomation.com/u/Stevenson.Yuan)\
**Post date:** [June 5, 2019, 5:14pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/3 "2019-06-05T17:14:11Z")

</div>

Also datetime.now() doesn’t return a string,

```auto
from datetime import datetime
FMT = '%Y-%m-%d %H:%M:%S' 
print datetime.now()
datetime.strptime(str(datetime.now()),FMT)

```

If you check the type of datetime it’s \<class ‘datetime.datetime’\>

---

<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:** [June 5, 2019, 5:15pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/4 "2019-06-05T17:15:35Z")

</div>

Oh, yeah, I didn’t even notice you were using datetime objects. For general sanity/interoperability reasons, you’re probably better off using our [`system.date`](https://docs.inductiveautomation.com/display/DOC80/system.date) functions, rather than the `datetime` library for Python.

---

<div class="post-metadata">

**Author:** ![RForshey](https://avatars.discourse-cdn.com/v4/letter/r/dc4da7/32.png) [@RForshey](https://forum.inductiveautomation.com/u/RForshey)\
**Post date:** [June 5, 2019, 5:43pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/5 "2019-06-05T17:43:14Z")

</div>

You guys are awesome, thanks for the help!

---

<div class="post-metadata">

**Author:** ![RForshey](https://avatars.discourse-cdn.com/v4/letter/r/dc4da7/32.png) [@RForshey](https://forum.inductiveautomation.com/u/RForshey)\
**Post date:** [June 25, 2019, 11:53pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/6 "2019-06-25T23:53:41Z")

</div>

A follow on question:

The Dictionary has basically 3 levels and using the strategy given before, I’m able to get all of the rows from the second and third levels. But I am not able to use the script for the first level. I’ve come up with a temporary work around (Select 1, 2 3) but would rather not use this in the long run. As you can see in the below script, I’m getting the data from “data” and operDict. I’ve tried setting up the “data” portion of the script with the newrow type stuff from later in the script but it fails. Any ideas?

```auto
from urllib import urlencode
from datetime import datetime
FMT = '%Y-%m-%d %H:%M:%S'
if event.source.parent.getComponent('Select 1').selected:
	x = 0
if event.source.parent.getComponent('Select 2').selected:
	x = 1
if event.source.parent.getComponent('Select 3').selected:
	x = 2	
#Salord = event.source.parent.getComponent('Work_Order').selectedStringValue
Salord = event.source.parent.getComponent('WO_List').selectedStringValue
args = {"sales-order": Salord, "token": "cfapiKnJ4Td2WQ8hf"}
Server = event.source.parent.getComponent('Table_Select').Server
response = system.net.httpGet("http://" + Server + ":8080/cellfusion/api/v1/orders/details?" + urlencode(args))

#stores jsonString into a python object/dict
jsonDict = system.util.jsonDecode(response)

#Assigns the variable, data, to the dictionary inside of jsonDict
data = jsonDict['data'][x]
operDict = jsonDict['data'][x]['operations'] 

id = str(data['id'])
mfgstatusCode = str(data['mfgstatus-code'])
assemblyid = str(data['assembly-id'])
assemblyCode = str(data['assembly-code'])
qty = str(data['mfgqty'])
description = str(data['assembly-dscr'])
workorder = str(data['salord'])
status = str(data['mfgstatus-dscr'])
opsopen = str(data['opsopen'])
opsclosed = str(data['opsclosed'])
currentop = str(data['currentop-code'])
laborhrs = str(round(data['actualtime']/3600.0,2))

headers = ['ID', 'Status Code', 'Assembly ID', 'Top Level PN', 'Quantity', 'Description', 'Work Order', 'Status', 'Ops Open', 'Ops Closed', 'Current Op', 'Labor Hrs']
rows = [
[id, mfgstatusCode, assemblyid, assemblyCode, qty, description, workorder, status, opsopen, opsclosed, currentop, laborhrs] ,  
]

dataset = system.dataset.toDataSet(headers, rows)
event.source.parent.getComponent('Head_Table').data = dataset

# create holder list
rows = []
 
for row in operDict:
	newrow = []
	newrow.append(row['fwork-code'])
	newrow.append(row['fwork-id'])
	newrow.append(row['fwork-dscr'])
	newrow.append(row['from']) 
	newrow.append(row['to'])
	try:
		if row['from']:
			d1 = row['from']
		else:
			d1 = "No Date"
	except ValueError:
		d1 = "No Date"
	try:
		if row['to']:
			d2 = row['to']
		else:
			d2 = "No Date"
	except ValueError:
		d2 = "No Date"
	try:
		if row['from']:
			newrow.append(datetime.strptime(d2, FMT) - datetime.strptime(d1, FMT))
		else: 
			newrow.append('0')
	except ValueError:
		"No Value"
	try: 
		if row['actualtime']:
			newrow.append(round(row['actualtime']/3600.0,2))
		else:
			newrow.append('0')
	except ValueError:
		'0'
	newrow.append(row['status'])

# add our new row (casting each element to a string) to the overall rows list
	rows.append([str(r) for r in newrow])

headers = ['OP Code', 'ID', 'Description', 'Start', 'End', 'Elapsed', 'Labor Hrs', 'Status']
dataset = system.dataset.toDataSet(headers, rows)
event.source.parent.getComponent('Oper_Table').data = dataset

```

---

<div class="post-metadata">

**Author:** ![Stevenson.Yuan](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Stevenson.Yuan](https://forum.inductiveautomation.com/u/Stevenson.Yuan)\
**Post date:** [July 9, 2019, 3:01pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/7 "2019-07-09T15:01:19Z")

</div>

can you snippet the json structure you’re working with?

Unless the structure is different between 1,2, and 3- it shouldn’t matter.

---

<div class="post-metadata">

**Author:** ![RForshey](https://avatars.discourse-cdn.com/v4/letter/r/dc4da7/32.png) [@RForshey](https://forum.inductiveautomation.com/u/RForshey)\
**Post date:** [October 24, 2019, 5:58pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/8 "2019-10-24T17:58:09Z")

</div>

“id”: “31138”,  
“code”: “31138”,  
“salord”: “001000032409”,  
“from”: “2019-10-08 15:22:21.0”,  
“to”: “”,  
“mfgstatus-code”: “0003”,  
“mfgstatus-dscr”: “In process”,  
“mfgqty”: 1,  
“assembly-id”: “3233”,  
“assembly-code”: “NEW-VXT”,  
“assembly-dscr”: “GENERIC TEMPLATE FOR VXT GAS BOXES”,  
“opsopen”: 5,  
“opsclosed”: 2,  
“currentop-id”: “37446”,  
“currentop-code”: “0030”,  
“currentop-dscr”: “ENCLOSURE ASSEMBLY”,  
“currentevent-id”: “50808”,  
“currentevent-code”: “0300”,  
“currentevent-dscr”: “VERIFICATION BEFORE FUNCTIONAL TEST”,  
“actualtime”: 179707,  
“operations”: [  
{  
“fwork-id”: “36824”,  
“fwork-code”: “0010”,  
“fwork-dscr”: “MAIN ASSEMBLY”,  
“from”: “2019-10-08 15:22:22.0”,  
“to”: “2019-10-12 14:19:16.0”,  
“actualtime”: 9395,  
“status”: “Closed”,  
“events”: [  
{  
“fwork-id”: “50784”,  
“fwork-code”: “CRADLE/WELD ASSY”,  
“fwork-dscr”: “CRADLE/WELD ASSY”,  
“start”: “2019-10-08 15:22:22.0”,  
“end”: “2019-10-12 14:19:16.0”,  
“actualtime”: 116,  
“status”: “Closed”

Here’s a bit of result. As you can see, there are three dictionarys: Data, Operations, and Events. I can iterate through Operations and Events, but not through Data. In a given query, there are multiple data(ID), Operations(fwork-id) and Events(fwork-id). I’m able to iterate and pull all of the rows for the Operations and Events, but get the “unicode indices must be integers” error when trying to iterate through the data dictionary. Any ideas?

---

<div class="post-metadata">

**Author:** ![Stevenson.Yuan](https://avatars.discourse-cdn.com/v4/letter/s/ac91a4/32.png) [@Stevenson.Yuan](https://forum.inductiveautomation.com/u/Stevenson.Yuan)\
**Post date:** [October 29, 2019, 2:35pm UTC](https://forum.inductiveautomation.com/t/python-issue-replacing-an-empty-key/25583/9 "2019-10-29T14:35:24Z")

</div>

Not sure if it’s a typo in the example, but there is no “Data” key in the dictionary.

If there’s a possibility a key may not exist because it’s empty.

A couple of things you can try is adding a check if the key exists:

```auto
if "Data" in dictionary.keys():

```

Another option is to use the “get” function:

```auto
dictionary.get("Data",[])

```

this tells the dictionary to retrieve the object in Data, or return an empty list if the key is not found (ie. default value).

This way if you attempt to iterate a non-existent key it will iterate an empty list and just return nothing back.
