MalformedJsonException: Invalid escape sequence

I'm running into an issue while trying to add text to templates, via passed parameters, that are then added to a template canvas, at runtime. The code works great until it encounters certain special characters, such as the degree symbol, at which point it starts throwing WARN Vision.TemplateCanvas - Unable to parse parameters as JSON on row X (where X is the row #). MalformedJsonException: Invalid escape sequence at line 1 column 35.

The code I've been working with to add a line to a dataset that tells the template canvas how to create the cell is below:

	rowData = {"rid":5,"description":"45° angle"}
	def buildDescCell(this):
		tid = "rid" + str(this.rowData["rid"]) + "-" + str(1) # A unique name for the template being added to the canvas
		template = "TATemplate" # The name of the template being used; this one's a TextArea, but same happens with basic Labels
		constraints = "grow,cell 1 1 1 1,w 50px"  #This line is simplified for this example...
		inputStr = this.rowData["description"].replace('°', '') #Works until the .replace() is removed/commented out
		params = {"tempID": tid ,"text": inputStr} #Parameters to be passed to the template being added to the TemplateCanvas
		cList = [tid,template,constraints,0,0,None,None,params] #The final construction of the TemplateCanvas data for a single cell to be added
		return cList #Returned data is added to tableData = [] via tableData.append(data)

Now the above code works as it is, but as soon as you remove/comment out the .replace('°', '') call on 'inputStr' is when the MalformedJsonException errors start getting thrown by the TemplateCanvas object.

To put the data into the TemplateCanvas, I convert it to a usable dataset using:

dsHeader = ["name","template","layout","x","y","width","height","parameters"]
def getTableDataSet(this):
	data = system.dataset.toDataSet(this.dsHeader, this.tableData)
	print data.getValueAt(66,7) # The line in question; Returns: {'tempID': 'rid5-1', 'text': '45\xc2\xb0 Angle'}
	return data # Inside of a button `TemplateCanvas.templates = <this returned dataSet>` applies the dataset to the template canvas in order to display the cells.

What am I doing wrong that's causing this to throw the exception? I'm guessing I need to encode the symbol differently, but I'm not sure what is acceptable to get it to stop throwing json exceptions but still display the ° symbol.

I've tried:

import json
...
json.dumps(inputStr) 
...

which gets rid of the error, but then I get the string: "45\u00b0 Angle" showing up in my TextArea/Label, "" included. I've also tried unicode(inputStr,"utf-8"), but that breaks even more text in other cells. I've run out of ideas to try...

I've seen this thread: Degree Symbol not supported in system.util.jsonDecode? But still can't seem to get anything working. I feel like I'm missing something right in front of my face, but am too frustrated to see it...

You are using jython's json module. Jython's stdlib is known to be mostly broken when unicode is involved. Don't use it.

Use the Ignition-supplied system functions instead.

Also, wherever you might provide unicode symbols in jython string constants, make sure you mark them as unicode with the u"some ° String" syntax.

I think that's the biggest problem here.
Pasting 45° angle directly into the template canvas customizer works fine for me:

1 Like

I kind of figured it wasn't the ° symbol, as I have another piece of code that's far more convoluted (this code is my attempt at cleaning that up, but turned into a complete rewrite...) that doesn't throw the error, but I also don't specify in either one to use the system.util vs Jython's stdlib, so I'm not sure why that code works and this doesn't.

What in the code I showed points it to using the Jython stdlib? If you're referring solely to the import json part, that's only something I've tried on the side and is not in use when I get the error.

Update: I looked a little closer at my old code and noticed I was passing the parameters as a stringified dictionary in my old code, whereas this code uses an actual dictionary for the params. Converting it to a stringified dict fixes the issue.

ie:

params = {"tempID": tid ,"text": inputStr}

is now:

params = '{"tempID":'+tid+',"text":"'+unicode(inputStr)+'"}'

and this works fine while displaying the ° symbol. Without unicode() works, but I get the extra character 45° Angle before the degree symbol like I struggled with prior. So my mistake was using an actual dictionary, not a string representing a dictionary, like I had in my old code. The odd part was that it worked until special characters were introduced...

Make a regular ol' Python data structure, using unicode subsequences as appropriate, and convert to json with system.util.jsonEncode at the "last moment" before inserting into the template canvas dataset:

params = {
	"text": u"90° angle"
}

headers = ["name","template","parameters","x","y","width","height","layout","z"]
data = [[
	"abc",
	"label",
	system.util.jsonEncode(params),
	0,
	0,
	200,
	200,
	"n/a",
	0
]]

ds = system.dataset.toDataSet(headers, data)
event.source.parent.getComponent('Template Canvas').templates = ds

image

2 Likes

I was just testing that, myself, lol... Heck of a lot quicker to type out, and easier to read, than the manual string conversion.

Could've swore I'd tried that at one point but it didn't work... probably was a typo somewhere.