Improves behaviors related to bibtex decoding error.
- from editor input in add and edit commands, - from files in import command.
This commit is contained in:
parent
d8dc386a18
commit
8a7d143261
@ -11,6 +11,7 @@ from .. import templates
|
||||
from .. import apis
|
||||
from .. import pretty
|
||||
from .. import utils
|
||||
from .. import endecoder
|
||||
from ..completion import CommaSeparatedTagsCompletion
|
||||
|
||||
|
||||
@ -57,12 +58,13 @@ def bibentry_from_editor(conf, ui, rp):
|
||||
bibstruct.verify_bibdata(bibentry)
|
||||
# REFACTOR Generate citykey
|
||||
again = False
|
||||
except ValueError:
|
||||
|
||||
except endecoder.EnDecoder.BibDecodingError:
|
||||
again = ui.input_yn(
|
||||
question='Invalid bibfile. Edit again ?',
|
||||
question='Invalid bibfile. Edit again?',
|
||||
default='y')
|
||||
if not again:
|
||||
ui.exit(0)
|
||||
ui.exit()
|
||||
|
||||
return bibentry
|
||||
|
||||
|
@ -64,9 +64,14 @@ def command(conf, args):
|
||||
'as `{}`.'.format(citekey, new_paper.citekey)))
|
||||
else:
|
||||
ui.info(('Paper `{}` was successfully edited.'.format(
|
||||
citekey)))
|
||||
citekey)))
|
||||
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:
|
||||
options = ['overwrite', 'edit again', 'abort']
|
||||
choice = options[ui.input_choice(
|
||||
|
@ -27,7 +27,7 @@ def parser(subparsers, conf):
|
||||
return parser
|
||||
|
||||
|
||||
def many_from_path(bibpath):
|
||||
def many_from_path(ui, bibpath):
|
||||
"""Extract list of papers found in bibliographic files in path.
|
||||
|
||||
The behavior is to:
|
||||
@ -49,11 +49,17 @@ def many_from_path(bibpath):
|
||||
|
||||
biblist = []
|
||||
for filepath in all_files:
|
||||
biblist.append(coder.decode_bibdata(read_text_file(filepath)))
|
||||
try:
|
||||
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 = {}
|
||||
for b in biblist:
|
||||
for k, b in b.items():
|
||||
if k in papers:
|
||||
ui.warning('Duplicated citekey {}. Keeping last.'.format(k))
|
||||
try:
|
||||
papers[k] = Paper(k, b)
|
||||
papers[k].added = datetime.datetime.now()
|
||||
@ -75,7 +81,7 @@ def command(conf, args):
|
||||
|
||||
rp = repo.Repository(conf)
|
||||
# Extract papers from bib
|
||||
papers = many_from_path(bibpath)
|
||||
papers = many_from_path(ui, bibpath)
|
||||
keys = args.keys or papers.keys()
|
||||
for k in keys:
|
||||
p = papers[k]
|
||||
|
@ -66,6 +66,16 @@ class EnDecoder(object):
|
||||
* 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.display_order = BIBFIELD_ORDER
|
||||
|
||||
@ -103,7 +113,10 @@ class EnDecoder(object):
|
||||
return entry
|
||||
|
||||
def decode_bibdata(self, bibdata):
|
||||
""""""
|
||||
"""Decodes bibdata from string.
|
||||
|
||||
If the decoding fails, returns a BibParseError.
|
||||
"""
|
||||
try:
|
||||
entries = bp.bparser.BibTexParser(
|
||||
bibdata, common_strings=True,
|
||||
@ -121,4 +134,5 @@ class EnDecoder(object):
|
||||
except Exception:
|
||||
import traceback
|
||||
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()
|
||||
return True # never happens
|
||||
|
||||
|
||||
class InputUI(PrintUI):
|
||||
"""UI class. Stores configuration parameters and system information.
|
||||
"""
|
||||
@ -118,7 +119,7 @@ class InputUI(PrintUI):
|
||||
except EOFError:
|
||||
self.error('Standard input ended while waiting for answer.')
|
||||
self.exit(1)
|
||||
return ustr(data) #.decode('utf-8')
|
||||
return ustr(data) #.decode('utf-8')
|
||||
|
||||
def input_choice_ng(self, options, option_chars=None, default=None, question=''):
|
||||
"""Ask the user to chose between a set of options. The user is asked
|
||||
|
@ -32,7 +32,7 @@ class TestDOI2Bibtex(unittest.TestCase):
|
||||
|
||||
def test_parse_fails_on_incorrect_DOI(self):
|
||||
bib = doi2bibtex('999999')
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(EnDecoder.BibDecodingError):
|
||||
self.endecoder.decode_bibdata(bib)
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ class TestISBN2Bibtex(unittest.TestCase):
|
||||
|
||||
def test_parse_fails_on_incorrect_ISBN(self):
|
||||
bib = doi2bibtex('9' * 13)
|
||||
with self.assertRaises(ValueError):
|
||||
with self.assertRaises(EnDecoder.BibDecodingError):
|
||||
self.endecoder.decode_bibdata(bib)
|
||||
|
||||
|
||||
|
@ -147,6 +147,11 @@ class TestEnDecode(unittest.TestCase):
|
||||
self.assertIn('author', 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__':
|
||||
unittest.main()
|
||||
|
@ -337,11 +337,20 @@ class TestAdd(URLContentTestCase):
|
||||
def test_add_no_citekey_fails(self):
|
||||
# See #113
|
||||
cmds = ['pubs init',
|
||||
('pubs add', [str_fixtures.bibtex_no_citekey]),
|
||||
('pubs add', [str_fixtures.bibtex_no_citekey, 'n']),
|
||||
]
|
||||
with self.assertRaises(FakeSystemExit):
|
||||
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):
|
||||
|
||||
@ -690,6 +699,32 @@ class TestUsecase(DataCommandTestCase):
|
||||
]
|
||||
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):
|
||||
cmds = ['pubs init',
|
||||
('pubs add', [str_fixtures.bibtex_external0]),
|
||||
|
Loading…
x
Reference in New Issue
Block a user