How to handle the exception ‘IllegalCharacterError’ in openpyxl

The python module openpyxl may sometimes raise the exception IllegalCharacterError (see: https://openpyxl.readthedocs.io/en/stable/api/openpyxl.utils.exceptions.html for further details).

The raised exception however, does not hint at a way of handling the exception, nor does the documentation at the moment.

I’ve written the function below, that escapes all of the necessary characters. You can for instance use it when inserting a string into a cell, like: wb['A1'].value = escape_xlsx_string('Your string with a char \x00 that would normally raise an exception').

The illegal character \x00 is then escaped, so that the inserted string becomes: ‘Your string with a char \x00 that would normally raise an exception' – note that the \x00 is “spelled out” as and not inserted as the NULL character, that would otherwise cause the exception to be raised.

The list of illegal characters was derived by testing every single unicode codepoint, so it should be complete. Interrestingly the illegal characters are all ASCII control characters > 32. But the other unicode control characters seems to be allowed.

def escape_xlsx_char(ch):
	illegal_xlsx_chars = {
	'\x00':'\\x00',	#	NULL
	'\x01':'\\x01',	#	SOH
	'\x02':'\\x02',	#	STX
	'\x03':'\\x03',	#	ETX
	'\x04':'\\x04',	#	EOT
	'\x05':'\\x05',	#	ENQ
	'\x06':'\\x06',	#	ACK
	'\x07':'\\x07',	#	BELL
	'\x08':'\\x08',	#	BS
	'\x0b':'\\x0b',	#	VT
	'\x0c':'\\x0c',	#	FF
	'\x0e':'\\x0e',	#	SO
	'\x0f':'\\x0f',	#	SI
	'\x10':'\\x10',	#	DLE
	'\x11':'\\x11',	#	DC1
	'\x12':'\\x12',	#	DC2
	'\x13':'\\x13',	#	DC3
	'\x14':'\\x14',	#	DC4
	'\x15':'\\x15',	#	NAK
	'\x16':'\\x16',	#	SYN
	'\x17':'\\x17',	#	ETB
	'\x18':'\\x18',	#	CAN
	'\x19':'\\x19',	#	EM
	'\x1a':'\\x1a',	#	SUB
	'\x1b':'\\x1b',	#	ESC
	'\x1c':'\\x1c',	#	FS
	'\x1d':'\\x1d',	#	GS
	'\x1e':'\\x1e',	#	RS
	'\x1f':'\\x1f'}	#	US
	
	if ch in illegal_xlsx_chars:
		return illegal_xlsx_chars[ch]
	
	return ch
	
#
# Wraps the function escape_xlsx_char(ch).
def escape_xlsx_string(st):
	
	return ''.join([escape_xlsx_char(ch) for ch in st])

I am aware that the title says ‘handle the exception’ – you could do that by inserting strings into the cell and handling the exception, when it occours, using the function above.
Another method could be just to use the function every time.

Read the ADXL345 accelerometer with Raspberry Pi, using SPI bus

I recently had to read the Analog Devices ADXL345 accelerometer, using SPI. So I used the Raspberry Pi. I only needed to verify the functionality in Python, so the code do have some rough edges, when it comes to the calculation of the gravity, but the code that reads the device is correct.

Note: You need to have the python-dev package installed, along with the SpiDev. You can get the former, using apt-get, but you have to install SpiDev manually.

Another note, and this is important; You shouldn’t set the spi.mode = 3 field before calling the open() function. I have no idea what so ever why, but the SPI on the Raspberry Pi, will absolutely not work for me, if I do that.

The code is provided, here below:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Example on how to read the ADXL345 accelerometer.
# Kim H. Rasmussen, 2014
import time
import spidev

# Setup SPI
spi = spidev.SpiDev()
#spi.mode = 3    <-- Important: Do not do this! Or SPI won't work as intended, or even at all.
spi.open(0,0)
spi.mode = 3

# Read the Device ID (should be xE5)
id = spi.xfer2([128,0])
print 'Device ID (Should be 0xE5):\n'+str(hex(id[1])) + '\n'

# Read the offsets
xoffset = spi.xfer2([30 | 128,0])
yoffset = spi.xfer2([31 | 128,0])
zoffset = spi.xfer2([32 | 128,0])
print 'Offsets: '
print xoffset[1]
print yoffset[1]
print str(zoffset[1]) + "\n\nRead the ADXL345 every half second:"

# Initialize the ADXL345
def initadxl345():
    # Enter power saving state
    spi.xfer2([45, 0])

    # Set data rate to 100 Hz
    spi.xfer2([44, 10])

    # Enable full range (10 bits resolution) and +/- 16g 4 LSB
    spi.xfer2([49, 16])

    # Enable measurement
    spi.xfer2([45, 8])

# Read the ADXL x-y-z axia
def readadxl345():
    rx = spi.xfer2([242,0,0,0,0,0,0])

    # 
    out = [rx[1] | (rx[2] << 8),rx[3] | (rx[4] << 8),rx[5] | (rx[6] << 8)]
    # Format x-axis
    if (out[0] & (1<<16 - 1 )):
        out[0] = out[0] - (1<<16)
    out[0] = out[0] * 0.004 * 9.82
    # Format y-axis
    if (out[1] & (1<<16 - 1 )):
        out[1] = out[1] - (1<<16)
    out[1] = out[1] * 0.004 * 9.82
    # Format z-axis
    if (out[2] & (1<<16 - 1 )):
        out[2] = out[2] - (1<<16)
    out[2] = out[2] * 0.004 * 9.82

    return out

# Initialize the ADXL345 accelerometer
initadxl345()

# Read the ADXL345 every half second
timeout = 0.5
while(1):
    axia = readadxl345()
    # Print the reading
    print axia[0]
    print axia[1]
    print str(axia[2]) + '\n'

    elapsed = time.clock()
    current = 0
    while(current < timeout):
        current = time.clock() - elapsed

Python Socket

Details to come.
Here’s a short description in the meanwhile:

This is a class I wrote for a host, which should handle some requests, given by clients.
The part to notice here is the way select() is used. I found that socket.recv() was a blocking call and since any method of trying to make it non-blocking failed with some error, I had to use select(). Select reads from selectable inputs (ie. socket or user inputs), and returns a list of sockets with data read. You may then use socket.recv() on these sockets, because there is data avaiable and this won’t block the program while waiting for data.

class ClientHandler():
    # Initializes a client handler
    # Takes the host socket as argument
    def __init__(self, socket):
        self.hostsoc = socket
        self.sockets = [self.hostsoc]       
        self.clients = []                 

    # Automatically removes dead clients
    def serveclients(self):

        # Select available sockets
        rready, wready, err = select.select(self.sockets, [], [], 0)
        for s in rready:

            # If there was a new connection
            if s == self.hostsoc:                                                                                                                                                                                                           
                # Accept the new socket
                c, addr = s.accept()
                
                # Create new clients of the new socket
                client = Client(c, addr) 
                self.clients.append(client)

                # Append the new socket to the client handlers list of sockets                
                self.sockets.append(c)

            # If data was available on existing clients                                                                                                                      
            else:
                #Read                                                                                                                                                                                                              
                data = s.recv(1024)

                if data:
                    # Get the sender (client)
                    for c in self.clients:
                        if s == c.socket():
                            sender = c
                            break

                    # Append the data to the clients queue
                    sender.appenddata(data)

                    # Handle any complete requests there may be
                    sender.handle()                    

                    # Add data to client data queue
                    #print "Received %s" % ( data )

                else:
                    
                    # Mark the corresponding client as inactive ...
                    for c in self.clients:
                        if s == c.socket():
                            c.deactivate()
                            break                        

                    # ... and remove the socket descriptor from the list of avilable sockets                                                                      
                    self.sockets.remove(s)

                    # Close the socket
                    s.close()                                                        
        # Return            
        return True