Merge pull request #114 from pubs/fix/empty_key
Better checks and error message for empty key (Closes #113).
This commit is contained in:
commit
d685ec10aa
@ -12,8 +12,9 @@ TYPE_KEY = 'type'
|
|||||||
CONTROL_CHARS = ''.join(map(uchr, list(range(0, 32)) + list(range(127, 160))))
|
CONTROL_CHARS = ''.join(map(uchr, list(range(0, 32)) + list(range(127, 160))))
|
||||||
CITEKEY_FORBIDDEN_CHARS = '@\'\\,#}{~%/ ' # '/' is OK for bibtex but forbidden
|
CITEKEY_FORBIDDEN_CHARS = '@\'\\,#}{~%/ ' # '/' is OK for bibtex but forbidden
|
||||||
# here since we transform citekeys into filenames
|
# here since we transform citekeys into filenames
|
||||||
CITEKEY_EXCLUDE_RE = re.compile('[%s]'
|
CITEKEY_EXCLUDE_RE = re.compile(
|
||||||
% re.escape(CONTROL_CHARS + CITEKEY_FORBIDDEN_CHARS))
|
'[%s]' % re.escape(CONTROL_CHARS + CITEKEY_FORBIDDEN_CHARS))
|
||||||
|
|
||||||
|
|
||||||
def str2citekey(s):
|
def str2citekey(s):
|
||||||
key = unicodedata.normalize('NFKD', ustr(s)).encode('ascii', 'ignore').decode()
|
key = unicodedata.normalize('NFKD', ustr(s)).encode('ascii', 'ignore').decode()
|
||||||
@ -21,32 +22,40 @@ def str2citekey(s):
|
|||||||
# Normalize chars and remove non-ascii
|
# Normalize chars and remove non-ascii
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
def check_citekey(citekey):
|
def check_citekey(citekey):
|
||||||
|
if citekey is None or not citekey.strip():
|
||||||
|
raise ValueError(u"Empty citekeys are not valid")
|
||||||
# TODO This is not the right way to test that (17/12/2012)
|
# TODO This is not the right way to test that (17/12/2012)
|
||||||
if ustr(citekey) != str2citekey(citekey):
|
if ustr(citekey) != str2citekey(citekey):
|
||||||
raise ValueError(u"Invalid `{}` citekey; ".format(citekey) +
|
raise ValueError(u"Invalid `{}` citekey; ".format(citekey) +
|
||||||
u"utf-8 citekeys are not supported yet.\n"
|
u"utf-8 citekeys are not supported yet.\n"
|
||||||
u"See https://github.com/pubs/pubs/issues/28 for details.")
|
u"See https://github.com/pubs/pubs/issues/28 for details.")
|
||||||
|
|
||||||
|
|
||||||
def verify_bibdata(bibdata):
|
def verify_bibdata(bibdata):
|
||||||
if bibdata is None or len(bibdata) == 0:
|
if bibdata is None or len(bibdata) == 0:
|
||||||
raise ValueError(u"no valid bibdata")
|
raise ValueError(u"no valid bibdata")
|
||||||
if len(bibdata) > 1:
|
if len(bibdata) > 1:
|
||||||
raise ValueError(u"ambiguous: multiple entries in the bibdata.")
|
raise ValueError(u"ambiguous: multiple entries in the bibdata.")
|
||||||
|
|
||||||
|
|
||||||
def get_entry(bibdata):
|
def get_entry(bibdata):
|
||||||
verify_bibdata(bibdata)
|
verify_bibdata(bibdata)
|
||||||
for e in bibdata.items():
|
for e in bibdata.items():
|
||||||
return e
|
return e
|
||||||
|
|
||||||
|
|
||||||
def extract_citekey(bibdata):
|
def extract_citekey(bibdata):
|
||||||
citekey, entry = get_entry(bibdata)
|
citekey, entry = get_entry(bibdata)
|
||||||
return citekey
|
return citekey
|
||||||
|
|
||||||
|
|
||||||
def author_last(author_str):
|
def author_last(author_str):
|
||||||
""" Return the last name of the author """
|
""" Return the last name of the author """
|
||||||
return author_str.split(',')[0]
|
return author_str.split(',')[0]
|
||||||
|
|
||||||
|
|
||||||
def generate_citekey(bibdata):
|
def generate_citekey(bibdata):
|
||||||
""" Generate a citekey from bib_data.
|
""" Generate a citekey from bib_data.
|
||||||
|
|
||||||
@ -60,7 +69,7 @@ def generate_citekey(bibdata):
|
|||||||
first_author = entry[author_key][0]
|
first_author = entry[author_key][0]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
u"No author or editor defined: cannot generate a citekey.")
|
u"No author or editor defined: cannot generate a citekey.")
|
||||||
try:
|
try:
|
||||||
year = entry['year']
|
year = entry['year']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -69,6 +78,7 @@ def generate_citekey(bibdata):
|
|||||||
|
|
||||||
return str2citekey(citekey)
|
return str2citekey(citekey)
|
||||||
|
|
||||||
|
|
||||||
def extract_docfile(bibdata, remove=False):
|
def extract_docfile(bibdata, remove=False):
|
||||||
""" Try extracting document file from bib data.
|
""" Try extracting document file from bib data.
|
||||||
Returns None if not found.
|
Returns None if not found.
|
||||||
|
@ -58,6 +58,17 @@ tags: [AI, computer]
|
|||||||
added: '2013-11-14 13:14:20'
|
added: '2013-11-14 13:14:20'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Should not parse (see #113)
|
||||||
|
bibtex_no_citekey = """@Manual{,
|
||||||
|
title = {R: A Language and Environment for Statistical Computing},
|
||||||
|
author = {{R Core Team}},
|
||||||
|
organization = {R Foundation for Statistical Computing},
|
||||||
|
address = {Vienna, Austria},
|
||||||
|
year = {2017},
|
||||||
|
url = {https://www.R-project.org/},
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
sample_conf = """
|
sample_conf = """
|
||||||
[main]
|
[main]
|
||||||
|
@ -42,6 +42,10 @@ class TestAttributes(unittest.TestCase):
|
|||||||
self.assertEqual(self.p.tags, set())
|
self.assertEqual(self.p.tags, set())
|
||||||
self.p.remove_tag('ranking')
|
self.p.remove_tag('ranking')
|
||||||
|
|
||||||
|
def test_fails_with_empty_citekey(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
Paper(" ", fixtures.doe_bibdata)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -331,6 +331,14 @@ class TestAdd(URLContentTestCase):
|
|||||||
]
|
]
|
||||||
self.execute_cmds(cmds)
|
self.execute_cmds(cmds)
|
||||||
|
|
||||||
|
def test_add_no_citekey_fails(self):
|
||||||
|
# See #113
|
||||||
|
cmds = ['pubs init',
|
||||||
|
('pubs add', [str_fixtures.bibtex_no_citekey]),
|
||||||
|
]
|
||||||
|
with self.assertRaises(FakeSystemExit):
|
||||||
|
self.execute_cmds(cmds)
|
||||||
|
|
||||||
|
|
||||||
class TestList(DataCommandTestCase):
|
class TestList(DataCommandTestCase):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user