unt-libraries / pycallnumber

Parse, model, and manipulate any type of call number string.
BSD 3-Clause "New" or "Revised" License
63 stars 9 forks source link

Can't pickle a dict of cnranges #33

Open mbelvadi2 opened 3 years ago

mbelvadi2 commented 3 years ago

I am converting the entire LC class tree (with subranges) into a massive OrderedDict for use against fairly large lists of call numbers. Instead of having to rebuild the entire cnranges dict every time I run the program against another call number list file, I wanted to build it once, then create a pickle file with the dict that I could load.

But I get an error that from what I read on StackExchange has to do with the way you folks nested class definitions. Here's the relevant bits of my code: cnranges = OrderedDict() cnranges[cn_constant_name] = pycn.cnrange(range_start_string, range_end_string) # inside a for loop to populate the entire dict

typical start and end strings are things like 'AC1' and 'AC9999.9' - this part works fine with no errors so not a problem with my data; the cn_constant_name in this example would be the string 'AC1_AC9999.9' following your example names in your docs

pickle.dump(cnranges, open("cn_ranges.pkl", "wb"))

This last line produces this error: _pickle.PicklingError: Can't pickle <class 'pycallnumber.template.PartList'>: attribute lookup PartList on pycallnumber.template failed

Reading about other people's experiences with this error on StackExchange produced this information, which I'm guessing is relevant to your implementation of pycallnumber classes: 'Nesting classes makes pickle fail, since it relies on the path of the object inside your application to reconstruct it later.' and in another response: 'Python's pickle actually does not serializes classes: it does serialize instances, and put in the serialization a reference to each instance's class - and that reference is based on the class being bound to a name in a well defined module. So, instances of classes that don't have a module name, but rather live as attribute in other classes, or data inside lists and dictionaries, typically will not work.'