I am using Python 2.7 to parse a multi-layered list of GPS coordinates for plotting. The list is parsed recursively, having taken it from sqlite3, and at some point in the process hits a coordinate set that has been pickled. I'm needing a way of detecting it by type, meaning that when I hit pickled data, I need the program to recognize it, unpickle it and continue recursing on it.
Does pickled data have a type or class? So far, all I get are tuples, strings or unicode. I can't assume the data is at a certain depth in the list as sometimes there are multiple coordinate sets in one data stream. I simply want to use isinstance
to detect it.
My feeble attempt at solving this is below. (One problem - I cannot upgrade Python or use outside libraries due to this being a work computer.)
def plotCoordinates(self, coordinates, lineColor, lineWidth, tags):
if coordinates is None:
return
elif isinstance(coordinates, list):
if isinstance(coordinates[0], tuple): # COORDINATE TUPLE INSIDE THIS LIST?
# FOUND COORDINATES LIST, PLOT IT
for inx, coordinate in enumerate(coordinates):
longitude, latitude = coordinate
if inx == 0:
oldLatitude, oldLongitude = latitude, longitude
else:
self.plotLine(oldLatitude, oldLongitude, latitude, longitude, lineColor, lineWidth, tags, 1)
oldLatitude, oldLongitude = latitude, longitude
return
else: # JUST AN ORDINARY LIST, RECURSE ON IT
for item in coordinates:
self.plotCoordinates(item, lineColor, lineWidth, tags)
return
elif isinstance(coordinates, tuple):
# DIVE DOWN DEEPER INTO THE LIST
for item in coordinates:
self.plotCoordinates(item, lineColor, lineWidth, tags)
return
# FOUND PICKLED LIST. EXTRACT IT
elif isinstance(coordinates, str) or isinstance(coordinates, unicode):
self.plotCoordinates(pickle.loads(coordinates), lineColor, lineWidth, tags)
return
else:
# ERROR, UNKNOWN TYPE
print coordinates
print 'TYPE UNDETECTED: ' + str(type(coordinates))
return
In Python 2.7, type(pickled_object)
will always be str
. However, not every str
is a pickled object. isinstance("Hello", str) == True
, for example, but "Hello"
is not a pickled object. You will get a cryptic error if you do pickle.loads("Hello")
. There is no specific type for pickled objects that you can check for using isinstance
. A pickled object is simply a string that pickle
can convert to an object using loads
, because pickle
originally created it from an object with dumps
.
The most pythonic approach is to try to unpickle the object, and then let the pickle
module raise an exception if it cannot do it (as martineau referred to in the comments). The pickle
module is the one that creates all pickled objects, and it can best decide whether a string is a pickled object, by trying to get the original object back. If it succeeds, you have a nice unpickled object to plot. If it fails, then all you have is a string that you don't know what to do with, because it isn't a pickled object.
To implement this, after checking the tuple
case, in another elif
clause, do:
elif isinstance(coordinates, str):
# Strings might be pickled objects, let's see if this one is
try:
# Try to unpickle coordinates
obj = pickle.loads(coordinates)
except Exception:
# Coordinates failed to unpickle
# We cannot plot any coordinates with this input, then
print coordinates
print 'String could not be unpickled')
return
else:
# Unpickling created an object, now let's try to plot it
self.plotCoordinates(obj, lineColor, lineWidth, tags)
return
else:
# ERROR, UNKNOWN TYPE
print coordinates
print 'TYPE UNDETECTED: ' + str(type(coordinates))
return