Improves behaviors related to bibtex decoding error.

- from editor input in add and edit commands,
- from files in import command.
main
Olivier Mangin 7 years ago
parent d8dc386a18
commit 8a7d143261
No known key found for this signature in database
GPG Key ID: D72FEC1C3120A884

@ -11,6 +11,7 @@ from .. import templates
from .. import apis from .. import apis
from .. import pretty from .. import pretty
from .. import utils from .. import utils
from .. import endecoder
from ..completion import CommaSeparatedTagsCompletion from ..completion import CommaSeparatedTagsCompletion
@ -57,12 +58,13 @@ def bibentry_from_editor(conf, ui, rp):
bibstruct.verify_bibdata(bibentry) bibstruct.verify_bibdata(bibentry)
# REFACTOR Generate citykey # REFACTOR Generate citykey
again = False again = False
except ValueError:
except endecoder.EnDecoder.BibDecodingError:
again = ui.input_yn( again = ui.input_yn(
question='Invalid bibfile. Edit again ?', question='Invalid bibfile. Edit again?',
default='y') default='y')
if not again: if not again:
ui.exit(0) ui.exit()
return bibentry return bibentry

@ -67,6 +67,11 @@ def command(conf, args):
citekey))) citekey)))
break break
except coder.BibDecodingError:
if not ui.input_yn(question="Error parsing bibdata. Edit again?"):
ui.error("Aborting, paper not updated.")
ui.exit()
except repo.CiteKeyCollision: except repo.CiteKeyCollision:
options = ['overwrite', 'edit again', 'abort'] options = ['overwrite', 'edit again', 'abort']
choice = options[ui.input_choice( choice = options[ui.input_choice(

@ -27,7 +27,7 @@ def parser(subparsers, conf):
return parser return parser
def many_from_path(bibpath): def many_from_path(ui, bibpath):
"""Extract list of papers found in bibliographic files in path. """Extract list of papers found in bibliographic files in path.
The behavior is to: The behavior is to:
@ -49,11 +49,17 @@ def many_from_path(bibpath):
biblist = [] biblist = []
for filepath in all_files: for filepath in all_files:
try:
biblist.append(coder.decode_bibdata(read_text_file(filepath))) biblist.append(coder.decode_bibdata(read_text_file(filepath)))
except coder.BibDecodingError:
ui.error("Could not parse bibtex at {}. Aborting import.".format(filepath))
ui.exit()
papers = {} papers = {}
for b in biblist: for b in biblist:
for k, b in b.items(): for k, b in b.items():
if k in papers:
ui.warning('Duplicated citekey {}. Keeping last.'.format(k))
try: try:
papers[k] = Paper(k, b) papers[k] = Paper(k, b)
papers[k].added = datetime.datetime.now() papers[k].added = datetime.datetime.now()
@ -75,7 +81,7 @@ def command(conf, args):
rp = repo.Repository(conf) rp = repo.Repository(conf)
# Extract papers from bib # Extract papers from bib
papers = many_from_path(bibpath) papers = many_from_path(ui, bibpath)
keys = args.keys or papers.keys() keys = args.keys or papers.keys()
for k in keys: for k in keys:
p = papers[k] p = papers[k]

@ -66,6 +66,16 @@ class EnDecoder(object):
* encode_bibdata will try to recognize exceptions * encode_bibdata will try to recognize exceptions
""" """
class BibDecodingError(Exception):
message = "Could not parse provided bibdata:\n---\n{}\n---"
def __init__(self, bibdata):
self.data = bibdata
def __str__(self):
return self.message.format(self.data)
bwriter = bp.bwriter.BibTexWriter() bwriter = bp.bwriter.BibTexWriter()
bwriter.display_order = BIBFIELD_ORDER bwriter.display_order = BIBFIELD_ORDER
@ -103,7 +113,10 @@ class EnDecoder(object):
return entry return entry
def decode_bibdata(self, bibdata): def decode_bibdata(self, bibdata):
"""""" """Decodes bibdata from string.
If the decoding fails, returns a BibParseError.
"""
try: try:
entries = bp.bparser.BibTexParser( entries = bp.bparser.BibTexParser(
bibdata, common_strings=True, bibdata, common_strings=True,
@ -121,4 +134,5 @@ class EnDecoder(object):
except Exception: except Exception:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
raise ValueError('could not parse provided bibdata:\n{}'.format(bibdata)) raise self.BibDecodingError(bibdata)
# TODO: filter exceptions from pyparsing and pass reason upstream

@ -104,6 +104,7 @@ class PrintUI(object):
self.exit() self.exit()
return True # never happens return True # never happens
class InputUI(PrintUI): class InputUI(PrintUI):
"""UI class. Stores configuration parameters and system information. """UI class. Stores configuration parameters and system information.
""" """

@ -32,7 +32,7 @@ class TestDOI2Bibtex(unittest.TestCase):
def test_parse_fails_on_incorrect_DOI(self): def test_parse_fails_on_incorrect_DOI(self):
bib = doi2bibtex('999999') bib = doi2bibtex('999999')
with self.assertRaises(ValueError): with self.assertRaises(EnDecoder.BibDecodingError):
self.endecoder.decode_bibdata(bib) self.endecoder.decode_bibdata(bib)
@ -56,7 +56,7 @@ class TestISBN2Bibtex(unittest.TestCase):
def test_parse_fails_on_incorrect_ISBN(self): def test_parse_fails_on_incorrect_ISBN(self):
bib = doi2bibtex('9' * 13) bib = doi2bibtex('9' * 13)
with self.assertRaises(ValueError): with self.assertRaises(EnDecoder.BibDecodingError):
self.endecoder.decode_bibdata(bib) self.endecoder.decode_bibdata(bib)

@ -147,6 +147,11 @@ class TestEnDecode(unittest.TestCase):
self.assertIn('author', entry1) self.assertIn('author', entry1)
self.assertIn('institution', entry1) self.assertIn('institution', entry1)
def test_endecodes_raises_exception(self):
decoder = endecoder.EnDecoder()
with self.assertRaises(decoder.BibDecodingError):
decoder.decode_bibdata("@misc{I am not a correct bibtex{{}")
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

@ -337,11 +337,20 @@ class TestAdd(URLContentTestCase):
def test_add_no_citekey_fails(self): def test_add_no_citekey_fails(self):
# See #113 # See #113
cmds = ['pubs init', cmds = ['pubs init',
('pubs add', [str_fixtures.bibtex_no_citekey]), ('pubs add', [str_fixtures.bibtex_no_citekey, 'n']),
] ]
with self.assertRaises(FakeSystemExit): with self.assertRaises(FakeSystemExit):
self.execute_cmds(cmds) self.execute_cmds(cmds)
def test_add_edit_fails(self):
cmds = ['pubs init',
('pubs add',
['@misc{I am not a correct bibtex{{}', 'n']),
]
with self.assertRaises(FakeSystemExit) as cm:
self.execute_cmds(cmds)
self.assertEqual(cm.exception.code, 1)
class TestList(DataCommandTestCase): class TestList(DataCommandTestCase):
@ -690,6 +699,32 @@ class TestUsecase(DataCommandTestCase):
] ]
self.execute_cmds(cmds) self.execute_cmds(cmds)
def test_editor_succeeds_on_second_edit(self):
cmds = ['pubs init',
'pubs add data/pagerank.bib',
('pubs edit Page99', [
'', 'y',
'@misc{Page99, title="TTT", author="X. YY"}', '']),
('pubs list', [], '[Page99] YY, X. "TTT" \n')
]
self.execute_cmds(cmds)
def test_add_aborts(self):
with self.assertRaises(FakeSystemExit):
cmds = ['pubs init',
('pubs add New', ['']),
]
self.execute_cmds(cmds)
def test_add_succeeds_on_second_edit(self):
cmds = ['pubs init',
('pubs add', [
'', 'y',
'@misc{New, title="TTT", author="X. YY"}', '']),
('pubs list', [], '[New] YY, X. "TTT" \n')
]
self.execute_cmds(cmds)
def test_editor_success(self): def test_editor_success(self):
cmds = ['pubs init', cmds = ['pubs init',
('pubs add', [str_fixtures.bibtex_external0]), ('pubs add', [str_fixtures.bibtex_external0]),

Loading…
Cancel
Save