Adds update funciton for paper and required API and test updates.
- Adds update function that handle changes in citekey. - Adds copy functions to paper classes. - Adds tests. - FIX a few bugs.
This commit is contained in:
parent
0798280f9a
commit
83845d2360
@ -3,9 +3,8 @@ import os
|
||||
import unicodedata
|
||||
import re
|
||||
from cStringIO import StringIO
|
||||
import glob
|
||||
|
||||
from pybtex.database import Entry, BibliographyData
|
||||
from pybtex.database import Entry, BibliographyData, FieldDict, Person
|
||||
|
||||
import files
|
||||
|
||||
@ -49,6 +48,21 @@ def get_bibentry_from_string(content):
|
||||
return first_key, first_entry
|
||||
|
||||
|
||||
def copy_person(p):
|
||||
return Person(first=p.get_part_as_text('first'),
|
||||
middle=p.get_part_as_text('middle'),
|
||||
prelast=p.get_part_as_text('prelast'),
|
||||
last=p.get_part_as_text('last'),
|
||||
lineage=p.get_part_as_text('lineage'))
|
||||
|
||||
|
||||
def copy_bibentry(entry):
|
||||
fd = FieldDict(entry.fields.parent, entry.fields)
|
||||
persons = dict([(k, [copy_person(p) for p in v])
|
||||
for k, v in entry.persons.items()])
|
||||
return Entry(entry.type, fields=fd, persons=persons)
|
||||
|
||||
|
||||
def get_safe_metadata(metapath):
|
||||
if metapath is None:
|
||||
return None
|
||||
@ -81,7 +95,7 @@ class Paper(object):
|
||||
self.citekey = citekey
|
||||
|
||||
def __eq__(self, other):
|
||||
return (type(other) is Paper
|
||||
return (isinstance(self, Paper) and type(other) is type(self)
|
||||
and self.bibentry == other.bibentry
|
||||
and self.metadata == other.metadata
|
||||
and self.citekey == other.citekey)
|
||||
@ -168,6 +182,11 @@ class Paper(object):
|
||||
except (KeyError, IndexError):
|
||||
raise(NoDocumentFile('No file found in bib data.'))
|
||||
|
||||
def copy(self):
|
||||
return Paper(bibentry=copy_bibentry(self.bibentry),
|
||||
metadata=self.metadata.copy(),
|
||||
citekey=self.citekey)
|
||||
|
||||
@classmethod
|
||||
def load(cls, bibpath, metapath=None):
|
||||
key, entry = get_bibentry_from_file(bibpath)
|
||||
@ -211,12 +230,7 @@ class PaperInRepo(Paper):
|
||||
self.repo = repo
|
||||
|
||||
def get_document_path_in_repo(self):
|
||||
doc_dir = files.clean_path(self.repo.get_document_directory())
|
||||
found = glob.glob(doc_dir + "/%s.*" % self.citekey)
|
||||
if found:
|
||||
return found[0]
|
||||
else:
|
||||
raise NoDocumentFile
|
||||
return self.repo.find_document(self.citekey)
|
||||
|
||||
def get_document_path(self):
|
||||
try:
|
||||
@ -224,6 +238,14 @@ class PaperInRepo(Paper):
|
||||
except NoDocumentFile:
|
||||
return self.get_external_document_path()
|
||||
|
||||
def copy(self):
|
||||
return PaperInRepo.from_paper(self.as_paper().copy(), self.repo)
|
||||
|
||||
def as_paper(self):
|
||||
return Paper(bibentry=self.bibentry,
|
||||
metadata=self.metadata,
|
||||
citekey=self.citekey)
|
||||
|
||||
@classmethod
|
||||
def load(cls, repo, bibpath, metapath=None):
|
||||
key, entry = get_bibentry_from_file(bibpath)
|
||||
@ -231,3 +253,10 @@ class PaperInRepo(Paper):
|
||||
p = PaperInRepo(repo, bibentry=entry, metadata=metadata,
|
||||
citekey=key)
|
||||
return p
|
||||
|
||||
@classmethod
|
||||
def from_paper(cls, paper, repo):
|
||||
return PaperInRepo(repo,
|
||||
bibentry=paper.bibentry,
|
||||
metadata=paper.metadata,
|
||||
citekey=paper.citekey)
|
||||
|
@ -1,8 +1,9 @@
|
||||
import os
|
||||
import shutil
|
||||
import glob
|
||||
|
||||
import files
|
||||
from paper import Paper, PaperInRepo
|
||||
from paper import Paper, PaperInRepo, NoDocumentFile
|
||||
from color import colored
|
||||
import configs
|
||||
|
||||
@ -23,7 +24,8 @@ class Repository(object):
|
||||
config = configs.CONFIG
|
||||
self.config = config
|
||||
|
||||
# loading existing papers
|
||||
def has_paper(self, citekey):
|
||||
return citekey in self.citekeys
|
||||
|
||||
def paper_from_citekey(self, citekey):
|
||||
"""Load a paper by its citekey from disk, if necessary."""
|
||||
@ -64,7 +66,7 @@ class Repository(object):
|
||||
def add_paper(self, p):
|
||||
if p.citekey is None: # TODO also test if citekey is valid
|
||||
raise(ValueError("Invalid citekey: %s." % p.citekey))
|
||||
elif p.citekey in self.citekeys:
|
||||
elif self.has_paper(p.citekey):
|
||||
raise(ValueError("Citekey already exists in repository: %s"
|
||||
% p.citekey))
|
||||
self.citekeys.append(p.citekey)
|
||||
@ -76,22 +78,57 @@ class Repository(object):
|
||||
print "Added: %s" % p.citekey
|
||||
|
||||
def add_or_update(self, paper):
|
||||
if not paper.citekey in self.citekeys:
|
||||
if not self.has_paper(paper.citekey):
|
||||
self.add_paper(paper)
|
||||
else:
|
||||
self.save_paper(paper)
|
||||
|
||||
def update(self, paper, old_citekey=None, overwrite=False):
|
||||
"""Updates a paper, eventually changing its citekey.
|
||||
The paper should be in repository. If the citekey changes,
|
||||
the new citekey should be free excpet if the overwrite argumnent
|
||||
is set to True.
|
||||
"""
|
||||
if old_citekey is None:
|
||||
old_citekey = paper.citekey
|
||||
if old_citekey not in self.citekeys:
|
||||
raise(ValueError, 'Paper not in repository. Add first')
|
||||
else:
|
||||
if paper.citekey == old_citekey:
|
||||
self.save_paper(paper)
|
||||
else:
|
||||
if self.has_paper(paper.citekey):
|
||||
if not overwrite:
|
||||
raise(ValueError,
|
||||
"There is already a paper with citekey: %s."
|
||||
% paper.citekey)
|
||||
else:
|
||||
self.save_paper(paper)
|
||||
else:
|
||||
self.add_paper(paper)
|
||||
# Eventually move document file
|
||||
paper = PaperInRepo.from_paper(paper, self)
|
||||
try:
|
||||
path = self.find_document(old_citekey)
|
||||
self.import_document(paper.citekey, path)
|
||||
except NoDocumentFile:
|
||||
pass
|
||||
self.remove(old_citekey)
|
||||
|
||||
def remove(self, citekey):
|
||||
self.citetekeys.remove(citekey)
|
||||
self.citekeys.remove(citekey)
|
||||
paper = self.paper_from_citekey(citekey)
|
||||
for f in ('bib', 'meta'):
|
||||
shutil.rmtree(self.path_to_paper_file(citekey, f))
|
||||
# TODO change
|
||||
if paper.metadata['in-repo']:
|
||||
shutil.rmtree(self.path_to_paper_file(citekey, f))
|
||||
os.remove(self.path_to_paper_file(citekey, f))
|
||||
# Eventually remove associated document
|
||||
try:
|
||||
path = paper.get_document_path_in_repo()
|
||||
os.remove(path)
|
||||
except NoDocumentFile:
|
||||
pass
|
||||
|
||||
def save_paper(self, paper):
|
||||
if not paper.citekey in self.citekeys:
|
||||
if not self.has_paper(paper.citekey):
|
||||
raise(ValueError('Paper not in repository, first add it.'))
|
||||
paper.save_to_disc(self.path_to_paper_file(paper.citekey, 'bib'),
|
||||
self.path_to_paper_file(paper.citekey, 'meta'))
|
||||
@ -124,6 +161,7 @@ class Repository(object):
|
||||
self.papersdir = papersdir
|
||||
os.makedirs(os.path.join(self.papersdir, BIB_DIR))
|
||||
os.makedirs(os.path.join(self.papersdir, META_DIR))
|
||||
os.makedirs(self.get_document_directory())
|
||||
self.save()
|
||||
|
||||
def path_to_paper_file(self, citekey, file_):
|
||||
@ -140,6 +178,14 @@ class Repository(object):
|
||||
else:
|
||||
return os.path.join(self.papersdir, DOC_DIR)
|
||||
|
||||
def find_document(self, citekey):
|
||||
doc_dir = files.clean_path(self.get_document_directory())
|
||||
found = glob.glob(doc_dir + "/%s.*" % citekey)
|
||||
if found:
|
||||
return found[0]
|
||||
else:
|
||||
raise NoDocumentFile
|
||||
|
||||
def all_papers(self):
|
||||
for key in self.citekeys:
|
||||
yield self.paper_from_citekey(key)
|
||||
|
@ -22,10 +22,8 @@ entries:
|
||||
year: '1950'
|
||||
"""
|
||||
META = """
|
||||
filename: null
|
||||
extension: null
|
||||
external-document: null
|
||||
notes: []
|
||||
path: null
|
||||
"""
|
||||
|
||||
|
||||
@ -100,3 +98,22 @@ class TestSaveLoad(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
|
||||
class TestCopy(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.orig = Paper()
|
||||
self.orig.bibentry.fields['title'] = u'Nice title.'
|
||||
self.orig.bibentry.fields['year'] = u'2013'
|
||||
self.orig.bibentry.persons['author'] = [Person(u'John Doe')]
|
||||
self.orig.citekey = self.orig.generate_citekey()
|
||||
|
||||
def test_copy_equal(self):
|
||||
copy = self.orig.copy()
|
||||
self.assertEqual(copy, self.orig)
|
||||
|
||||
def test_copy_can_be_changed(self):
|
||||
copy = self.orig.copy()
|
||||
copy.bibentry.fields['year'] = 2014
|
||||
self.assertEqual(self.orig.bibentry.fields['year'], u'2013')
|
||||
|
@ -5,6 +5,7 @@ import os
|
||||
|
||||
import fixtures
|
||||
from papers.repo import Repository, _str_incr, _to_suffix, BIB_DIR, META_DIR
|
||||
from papers.paper import PaperInRepo
|
||||
|
||||
|
||||
class TestCitekeyGeneration(unittest.TestCase):
|
||||
@ -29,7 +30,7 @@ class TestCitekeyGeneration(unittest.TestCase):
|
||||
self.assertEqual(c, 'Turing1950b')
|
||||
|
||||
|
||||
class TestAddPaper(unittest.TestCase):
|
||||
class TestRepo(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.tmpdir = tempfile.mkdtemp()
|
||||
@ -37,6 +38,12 @@ class TestAddPaper(unittest.TestCase):
|
||||
self.repo.init(self.tmpdir)
|
||||
self.repo.add_paper(fixtures.turing1950)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
|
||||
class TestAddPaper(TestRepo):
|
||||
|
||||
def test_raises_value_error_on_existing_key(self):
|
||||
with self.assertRaises(ValueError):
|
||||
self.repo.add_paper(fixtures.turing1950)
|
||||
@ -49,5 +56,48 @@ class TestAddPaper(unittest.TestCase):
|
||||
self.assertTrue(os.path.exists(os.path.join(self.tmpdir, META_DIR,
|
||||
'Turing1950.meta')))
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.tmpdir)
|
||||
|
||||
class TestUpdatePaper(TestRepo):
|
||||
|
||||
def test_raises_value_error_on_unknown_paper(self):
|
||||
with self.assertRaises(ValueError):
|
||||
self.repo.update(fixtures.doe2013)
|
||||
with self.assertRaises(ValueError):
|
||||
self.repo.update(fixtures.doe2013, old_citekey='zou')
|
||||
|
||||
def test_raises_value_error_on_existing_destination(self):
|
||||
self.repo.add_paper(fixtures.doe2013)
|
||||
with self.assertRaises(ValueError):
|
||||
self.repo.update(fixtures.turing1950, old_citekey='Doe2013')
|
||||
|
||||
def test_updates_same_key(self):
|
||||
new = self.repo.paper_from_citekey('Turing1950')
|
||||
new.bibentry.fields['journal'] = u'Mind'
|
||||
self.repo.update(new)
|
||||
self.assertEqual(new, self.repo.paper_from_citekey('Turing1950'))
|
||||
|
||||
def test_updates_same_key_with_old_arg(self):
|
||||
new = self.repo.paper_from_citekey('Turing1950')
|
||||
new.bibentry.fields['journal'] = u'Mind'
|
||||
self.repo.update(new, old_citekey='Turing1950')
|
||||
self.assertEqual(new, self.repo.paper_from_citekey('Turing1950'))
|
||||
|
||||
def test_update_new_key_removes_old(self):
|
||||
self.repo.update(fixtures.doe2013, old_citekey='Turing1950')
|
||||
self.assertFalse(self.repo.has_paper('Turing1950'))
|
||||
|
||||
def test_update_new_key_updates(self):
|
||||
self.repo.update(fixtures.doe2013, old_citekey='Turing1950')
|
||||
self.assertTrue(self.repo.has_paper('Doe2013'))
|
||||
self.assertEqual(self.repo.paper_from_citekey('Doe2013'),
|
||||
PaperInRepo.from_paper(fixtures.doe2013, self.repo))
|
||||
|
||||
def test_update_new_key_moves_doc(self):
|
||||
self.repo.import_document('Turing1950',
|
||||
os.path.join(os.path.dirname(__file__),
|
||||
'data/pagerank.pdf'))
|
||||
self.repo.update(fixtures.doe2013, old_citekey='Turing1950')
|
||||
self.assertFalse(os.path.exists(os.path.join(
|
||||
self.repo.get_document_directory(), 'Turing1950.pdf')))
|
||||
self.assertTrue(os.path.exists(os.path.join(
|
||||
self.repo.get_document_directory(), 'Doe2013.pdf')))
|
||||
|
Loading…
x
Reference in New Issue
Block a user