#!/usr/bin/env python # panconvert.py - convert Pantry files created with versions 19, 20, # and 21 to work with version 22. usage = ('usage: panconvert.py FILE...\n' 'Converts Pantry native files created with versions\n' '19, 20, and 21 to work with version 22.\n' 'The original FILEs are not changed; the converted\n' 'file is written to FILE-new.\n') # hashlib new in python-2.5 try: import hashlib hasher = hashlib.sha1 except ImportError: import sha hasher = sha.sha import sys import shelve import errno from anydbm import error as anydbmError def getNewHash(traits): """ Given a dict of traits, returns a new hash. """ fingerPrint = ''.join([traits[traitNo].encode('utf-8') for traitNo in sorted(traits.keys())]) return hasher(fingerPrint).digest() ### The next three functions are only needed to convert ### recipe ingredients. They are not needed to convert ### any other aspect of a Pantry native file. def convertIngredient(ingredient): """ Convert a single ingredient (food or recipe). ingredient argument is a dict of dicts that is the food or recipe. Returns a dict of dicts e.g. {'traits':{1:u'hello'}, 'nutsPer100g:{203:4.5}} and so on. """ if 'ingredients' in ingredient: return convertRecipe(ingredient) return convertFood(ingredient) def convertFood(food): newTraits = dict([(traitNo, traitVal) for traitNo, traitVal in food['traits'].items() if traitVal != '']) newNutsPer100g = food['nuts'] newArbUnits = food['arbUnits'] return {'nutsPer100g':newNutsPer100g, 'arbUnits':newArbUnits, 'traits':newTraits} def convertRecipe(recipe): oldRTraits = recipe['rTraits'] newTraits = dict([(traitNo, traitVal) for traitNo, traitVal in recipe['traits'].items() if traitVal != '']) # old rTraits were yield (key 0) yieldDesc (key 1) # servings (key 2) and directions (key 3). # new corresponding values are yieldGrams (key 11) # yieldDesc (key 12) servings (key 13) # and directions (key 14). newTraits.update([(newKey, oldRTraits[oldKey]) for oldKey, newKey in ((0, 11), (1, 12), (2, 13), (3, 14)) if oldRTraits[oldKey] != '']) newArbUnits = recipe['arbUnits'] # handy bit of recursion newIngredients = [convertIngredient(ingredient) for ingredient in recipe['ingredients']] return {'traits':newTraits, 'arbUnits':newArbUnits, 'ingredients':newIngredients} if len(sys.argv[1:]) < 1: sys.stdout.write(usage) sys.exit(1) if sys.argv[1] == '-h' or sys.argv[1] == '--help': sys.stdout.write(usage) sys.exit() for oldFileName in sys.argv[1:]: try: oldShelf = shelve.open(oldFileName, 'r') except anydbmError: sys.stderr.write('panconvert: ERROR: File not found: %s\nAborting\n' % oldFileName) sys.exit(1) except: sys.stderr.write('panconvert: ERROR: could not open file %s.\n' 'Study the error message below for assistance.\n\n') raise try: newShelf = shelve.open(oldFileName + '-new', 'n') except: sys.stderr.write(('panconvert: ERROR: could not open new file' '%s-new.\nStudy the error message below for assistance.\n\n') % oldFileName) raise newShelf['VERSION'] = 22 newAllTraits = {} newAllArbUnits = {} oldAllRTraits = oldShelf.get('rTraits', {}) oldAllArbUnits = oldShelf.get('arbUnits', {}) for oldHash, oldTraitDict in oldShelf['traits'].items(): # convert traits and rTraits newTraitDict = dict([(oldTraitNo, oldValue) for oldTraitNo, oldValue in oldTraitDict.items() if oldValue != '']) try: oldRTraits = oldAllRTraits[oldHash] except KeyError: pass else: newTraitDict.update([(newTraitNo, oldRTraits[oldRTraitNo]) for oldRTraitNo, newTraitNo in ((0, 11), (1, 12), (2, 13), (3, 14)) if oldRTraits[oldRTraitNo] != '']) newHash = getNewHash(newTraitDict) newAllTraits[newHash] = newTraitDict # convert nuts try: oldNuts = oldShelf['nuts:%s' % oldHash] except KeyError: pass else: newShelf['n:%s' % newHash] = oldNuts # convert arbUnits try: oldArbUnits = oldAllArbUnits[oldHash] except KeyError: pass else: newAllArbUnits[newHash] = oldArbUnits # convert ingredients try: oldIngredients = oldShelf['ingredients:%s' % oldHash] except KeyError: pass else: newShelf['i:%s' % newHash] = [ convertIngredient(ingredient) for ingredient in oldIngredients] newShelf['traits'] = newAllTraits newShelf['arbUnits'] = newAllArbUnits newShelf.close() sys.stdout.write(('panconvert.py: converted file written to' ' %s-new\n') % oldFileName)