Reputation: 1293
I have three classes in my program,
Processes
contain Lanes
.
Lanes
contain Tasks
.
The objects are stored in each other as arrays with some other string information about the class
I'm trying to output the Process objects into JSON files but I keep getting the following error:
Object of type 'Process' is not JSON serializable
I'm fairly new to JSON processing so I don't understand why the objects are outputting this error.
I'm using the following code to print the Process
objects as JSON items:
def outputJSON(self):
for n in self.processes:
print(json.dumps(n, sort_keys=True, indent=4))
And these are the class objects:
class Task(object):
def __init__(self, name, UiD):
self.name = name
self.UiD = UiD
self.incoming = 'None'
self.outgoing = []
self.messageFlowIn = 'None'
self.messageFlowOut = 'None'
def __str__(self):
print(self.name +"\n")
print("Incoming Connection : \n" + self.incoming + "\n")
print("Outgoing Connections : ")
if len(self.outgoing) >= 1:
for n in self.outgoing:
print(n+"\n")
print("MessageFlowIn : " + self.messageFlowIn)
print("MessageFlowOut : " + self.messageFlowOut)
class Lane(object):
def __init__(self, name, associatedTasks):
self.name = name
self.associatedTasks = associatedTasks
class Process(object):
def __init__(self, name, associatedLaneNames):
self.name = name
self.associatedLaneNames = associatedLaneNames
self.laneObjects = []
How can I correctly output this data to a JSON file?
Upvotes: 1
Views: 3010
Reputation: 1293
Following @czr 's example; the solution was to go through and convert the object mappings into explicit dictionaries and then output an array of those nested dictionaries as follows:
def serialize(self):
processArray =[]
decisionItems = []
for process in self.processes:
processObj = {}
laneArray = []
for lane in process.laneObjects:
laneObj = {}
taskArray = []
for task in lane.associatedTasks:
taskObj = {}
for variableName, value in task.__dict__.items():
temp = value
placeHolderArray =[]
if isinstance(value, Task) or isinstance(value, StartEvent) or isinstance(value, EndEvent):
temp = value.name
taskObj[variableName] = temp
elif isinstance(value,list): #fix these lines
for n in value:
if isinstance(n, Task) or isinstance(n, StartEvent) or isinstance(n, EndEvent) or isinstance(n, DecisionBranch):
placeHolderArray.append(n.name)
taskObj[variableName] = placeHolderArray
elif isinstance(value, DecisionBranch):
taskObj['junctionPath'] = task.junctionPath
decisionBranch = {}
decisionBranch['name'] = value.name
decisionBranch['options'] = value.decisionBranch
decisionBranch['source'] = value.source
#taskObj['DecisionTree'] = decisionBranch
taskObj['URLs'] = task.urls
taskArray.append(taskObj)
laneObj['name'] = lane.name
laneObj['associatedTasks'] = taskArray
laneArray.append(laneObj)
processObj['name'] = process.name
processObj['laneObjects'] = laneArray
processArray.append(processObj)
return processArray
def outputJsonFile(self, fileContents):
tempString = self.fileName.split('.')
outputName = tempString[0]+'.json'
with open(outputName, 'w') as outfile:
outfile.write(json.dumps(fileContents, sort_keys=True, indent=4))
where fileContents
takes the returned processArray
from serialize()
The takeaway note is that iterating through a classes variables as follows:
for variableName, value in objectName.__dict__.items():
Allows you to retrieve the class variables and their respective values as a dictionary. As you is my code above, if it so happens that your value is an object then you have to explicitly define what properties you want to retrieve from that object by using python's handy isinstance()
:
if isinstance(value, Task) or isinstance(value, StartEvent) or isinstance(value, EndEvent):
temp = value.name
taskObj[variableName] = temp
If it is a python classic object, such as list; make sure to iterate through it explicitly:
elif isinstance(value,list): #fix these lines
for n in value:
if isinstance(n, Task) or isinstance(n, StartEvent) or isinstance(n, EndEvent) or isinstance(n, DecisionBranch):
placeHolderArray.append(n.name)
taskObj[variableName] = placeHolderArray
The reason for my initial confusion was my prior experience with google's GSON
for Java. That handy api simply takes a Java class and handily outputs a JSON formatted file for you. Unfortunately Python does not have such native libraries. The ideal solution would be to design your classes in ways such that they only contained native data types like strings,ints or lists of native datatypes. that way simply iterating over objectName.__dict__.item()
will provide a neat enough solution for you.
Upvotes: 0
Reputation: 658
Assuming that your attributes are simple values or list, you can use the class .__dict__
attribute to convert the class to a dict and then serialize it to a json, as a example:
p = Process('name', 'lanename')
p.laneObjects.extend([Lane('name', [Task('name', 'uid')])])
def to_dict(obj):
output ={}
for key, item in obj.__dict__.items():
if isinstance(item, list):
l = []
for item in item:
d = to_dict(item)
l.append(d)
output[key] = l
else:
output[key] = item
return output
to_dict(p)
This outputs:
{'associatedLaneNames': 'lanename',
'laneObjects': [{'associatedTasks': [{'UiD': 'uid',
'incoming': 'None',
'messageFlowIn': 'None',
'messageFlowOut': 'None',
'name': 'name',
'outgoing': []}],
'name': 'name'}],
'name': 'name'}
as a dict.
Upvotes: 2
Reputation: 55
Try using pickle to serialize and write to .JSON https://docs.python.org/3/library/pickle.html
Here's an example of how I save my data for a game I'm working on using pickle
def save():
file_player = "Save/%s/player.JSON" % functions.player.name
file_world = "Save/%s/world.JSON" % functions.player.name
file_counter = "Save/%s/counter.JSON" % functions.player.name
a = functions.player
b = world.world_map
c = functions.counter
save_player = open(file_player, 'wb')
save_world = open(file_world, 'wb')
save_counter = open(file_counter, 'wb')
pickle.dump(a, save_player, -1)
pickle.dump(b, save_world, -1)
pickle.dump(c, save_counter, -1)
save_player.close()
save_world.close()
save_counter.close()
This is saving 3 different classes from 3 different files, and dumping them into 1 save folder.
Upvotes: -1