kirienko / gourmet

Gourmet Recipe Manager
GNU General Public License v2.0
29 stars 14 forks source link

Mastercook import fails if mx2 file contains an empty IngR tag #328

Closed afoglia closed 3 years ago

afoglia commented 3 years ago

I was trying to import an mx2 file of all my recipes, and got a failure a dozen or so recipes in. I traced it to the fact my mx2 file has an empty IngR tag. Multiple recipes in my file have these empty IngR tags.

I suspect what happened is I added a blank row to the ingredient list in Mastercook, and that was what translated into the empty tag. (These recipes are over 15 years old.)

Steps to Reproduce

  1. Try to import an .mx2 file with an empty IngR tag.

Expected Behavior

The importer should just skip over empty IngR tags.

Current Behavior

The problem arises in MastercookXMLHandler.IngR_handler.

IngR_handler gets called twice for an empty tag. Once with start=True, end=False, attrs=None (or something else falsy).

The first call does nothing. The second call starts the commit. But self.ing has been cleared when the previous ingredient was commited (Importer.finish_ing), so the self.ing['unit'] in the debug call on line 194 raises a KeyError.

Error during XML Importer Traceback (most recent call last):
  File "/home/afoglia/src/gourmet/src/gourmet/threadManager.py", line 104, in run
    self.do_run()
  File "/home/afoglia/src/gourmet/src/gourmet/importers/xml_importer.py", line 80, in do_run
    self.parse = xml.sax.parse(self.fn, self.rh)
  File "/usr/lib/python3.8/xml/sax/__init__.py", line 33, in parse
    parser.parse(source)
  File "/usr/lib/python3.8/xml/sax/expatreader.py", line 111, in parse
    xmlreader.IncrementalParser.parse(self, source)
  File "/usr/lib/python3.8/xml/sax/xmlreader.py", line 125, in parse
    self.feed(buffer)
  File "/usr/lib/python3.8/xml/sax/expatreader.py", line 217, in feed
    self._parser.Parse(data, isFinal)
  File "../Modules/pyexpat.c", line 459, in EndElement
  File "/usr/lib/python3.8/xml/sax/expatreader.py", line 336, in end_element
    self._cont_handler.endElement(name)
  File "/home/afoglia/src/gourmet/src/gourmet/plugins/import_export/mastercook_import_plugin/mastercook_importer.py", line 117, in endElement
    handler(end=True)
  File "/home/afoglia/src/gourmet/src/gourmet/plugins/import_export/mastercook_import_plugin/mastercook_importer.py", line 194, in IngR_handler
    debug(
KeyError: 'unit'

Possible Solution

Just fixing the debug to use self.ing.get('unit') is not likely to work. commit_ing may not require 'unit', but the item information is still that of the previous IngR tag.

Instead, I suggest adding a check at the beginning of IngR_handler to reset the item-related attributes specific to MastercookXMLHandler.

if start:
    self.item = None

Then replace the if end: check with 'if end and self.item which will only commit an ingredient if one was read in.

Environment

cydanil commented 3 years ago

Thanks for taking the time to report the issue and to look for a solution!

Would you happen to have a short mx2 file to share?
We currently don't have one to test with...

cydanil commented 3 years ago

This is as fixed as I could make it, for the time being.
Should anyone have a problematic file, please share it!