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 unicodedata
|
||||||
import re
|
import re
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
import glob
|
|
||||||
|
|
||||||
from pybtex.database import Entry, BibliographyData
|
from pybtex.database import Entry, BibliographyData, FieldDict, Person
|
||||||
|
|
||||||
import files
|
import files
|
||||||
|
|
||||||
@ -49,6 +48,21 @@ def get_bibentry_from_string(content):
|
|||||||
return first_key, first_entry
|
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):
|
def get_safe_metadata(metapath):
|
||||||
if metapath is None:
|
if metapath is None:
|
||||||
return None
|
return None
|
||||||
@ -81,7 +95,7 @@ class Paper(object):
|
|||||||
self.citekey = citekey
|
self.citekey = citekey
|
||||||
|
|
||||||
def __eq__(self, other):
|
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.bibentry == other.bibentry
|
||||||
and self.metadata == other.metadata
|
and self.metadata == other.metadata
|
||||||
and self.citekey == other.citekey)
|
and self.citekey == other.citekey)
|
||||||
@ -168,6 +182,11 @@ class Paper(object):
|
|||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
raise(NoDocumentFile('No file found in bib data.'))
|
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
|
@classmethod
|
||||||
def load(cls, bibpath, metapath=None):
|
def load(cls, bibpath, metapath=None):
|
||||||
key, entry = get_bibentry_from_file(bibpath)
|
key, entry = get_bibentry_from_file(bibpath)
|
||||||
@ -211,12 +230,7 @@ class PaperInRepo(Paper):
|
|||||||
self.repo = repo
|
self.repo = repo
|
||||||
|
|
||||||
def get_document_path_in_repo(self):
|
def get_document_path_in_repo(self):
|
||||||
doc_dir = files.clean_path(self.repo.get_document_directory())
|
return self.repo.find_document(self.citekey)
|
||||||
found = glob.glob(doc_dir + "/%s.*" % self.citekey)
|
|
||||||
if found:
|
|
||||||
return found[0]
|
|
||||||
else:
|
|
||||||
raise NoDocumentFile
|
|
||||||
|
|
||||||
def get_document_path(self):
|
def get_document_path(self):
|
||||||
try:
|
try:
|
||||||
@ -224,6 +238,14 @@ class PaperInRepo(Paper):
|
|||||||
except NoDocumentFile:
|
except NoDocumentFile:
|
||||||
return self.get_external_document_path()
|
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
|
@classmethod
|
||||||
def load(cls, repo, bibpath, metapath=None):
|
def load(cls, repo, bibpath, metapath=None):
|
||||||
key, entry = get_bibentry_from_file(bibpath)
|
key, entry = get_bibentry_from_file(bibpath)
|
||||||
@ -231,3 +253,10 @@ class PaperInRepo(Paper):
|
|||||||
p = PaperInRepo(repo, bibentry=entry, metadata=metadata,
|
p = PaperInRepo(repo, bibentry=entry, metadata=metadata,
|
||||||
citekey=key)
|
citekey=key)
|
||||||
return p
|
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 os
|
||||||
import shutil
|
import shutil
|
||||||
|
import glob
|
||||||
|
|
||||||
import files
|
import files
|
||||||
from paper import Paper, PaperInRepo
|
from paper import Paper, PaperInRepo, NoDocumentFile
|
||||||
from color import colored
|
from color import colored
|
||||||
import configs
|
import configs
|
||||||
|
|
||||||
@ -23,7 +24,8 @@ class Repository(object):
|
|||||||
config = configs.CONFIG
|
config = configs.CONFIG
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
# loading existing papers
|
def has_paper(self, citekey):
|
||||||
|
return citekey in self.citekeys
|
||||||
|
|
||||||
def paper_from_citekey(self, citekey):
|
def paper_from_citekey(self, citekey):
|
||||||
"""Load a paper by its citekey from disk, if necessary."""
|
"""Load a paper by its citekey from disk, if necessary."""
|
||||||
@ -64,7 +66,7 @@ class Repository(object):
|
|||||||
def add_paper(self, p):
|
def add_paper(self, p):
|
||||||
if p.citekey is None: # TODO also test if citekey is valid
|
if p.citekey is None: # TODO also test if citekey is valid
|
||||||
raise(ValueError("Invalid citekey: %s." % p.citekey))
|
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"
|
raise(ValueError("Citekey already exists in repository: %s"
|
||||||
% p.citekey))
|
% p.citekey))
|
||||||
self.citekeys.append(p.citekey)
|
self.citekeys.append(p.citekey)
|
||||||
@ -76,22 +78,57 @@ class Repository(object):
|
|||||||
print "Added: %s" % p.citekey
|
print "Added: %s" % p.citekey
|
||||||
|
|
||||||
def add_or_update(self, paper):
|
def add_or_update(self, paper):
|
||||||
if not paper.citekey in self.citekeys:
|
if not self.has_paper(paper.citekey):
|
||||||
self.add_paper(paper)
|
self.add_paper(paper)
|
||||||
else:
|
else:
|
||||||
self.save_paper(paper)
|
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):
|
def remove(self, citekey):
|
||||||
self.citetekeys.remove(citekey)
|
self.citekeys.remove(citekey)
|
||||||
paper = self.paper_from_citekey(citekey)
|
paper = self.paper_from_citekey(citekey)
|
||||||
for f in ('bib', 'meta'):
|
for f in ('bib', 'meta'):
|
||||||
shutil.rmtree(self.path_to_paper_file(citekey, f))
|
os.remove(self.path_to_paper_file(citekey, f))
|
||||||
# TODO change
|
# Eventually remove associated document
|
||||||
if paper.metadata['in-repo']:
|
try:
|
||||||
shutil.rmtree(self.path_to_paper_file(citekey, f))
|
path = paper.get_document_path_in_repo()
|
||||||
|
os.remove(path)
|
||||||
|
except NoDocumentFile:
|
||||||
|
pass
|
||||||
|
|
||||||
def save_paper(self, paper):
|
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.'))
|
raise(ValueError('Paper not in repository, first add it.'))
|
||||||
paper.save_to_disc(self.path_to_paper_file(paper.citekey, 'bib'),
|
paper.save_to_disc(self.path_to_paper_file(paper.citekey, 'bib'),
|
||||||
self.path_to_paper_file(paper.citekey, 'meta'))
|
self.path_to_paper_file(paper.citekey, 'meta'))
|
||||||
@ -124,6 +161,7 @@ class Repository(object):
|
|||||||
self.papersdir = papersdir
|
self.papersdir = papersdir
|
||||||
os.makedirs(os.path.join(self.papersdir, BIB_DIR))
|
os.makedirs(os.path.join(self.papersdir, BIB_DIR))
|
||||||
os.makedirs(os.path.join(self.papersdir, META_DIR))
|
os.makedirs(os.path.join(self.papersdir, META_DIR))
|
||||||
|
os.makedirs(self.get_document_directory())
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def path_to_paper_file(self, citekey, file_):
|
def path_to_paper_file(self, citekey, file_):
|
||||||
@ -140,6 +178,14 @@ class Repository(object):
|
|||||||
else:
|
else:
|
||||||
return os.path.join(self.papersdir, DOC_DIR)
|
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):
|
def all_papers(self):
|
||||||
for key in self.citekeys:
|
for key in self.citekeys:
|
||||||
yield self.paper_from_citekey(key)
|
yield self.paper_from_citekey(key)
|
||||||
|
@ -22,10 +22,8 @@ entries:
|
|||||||
year: '1950'
|
year: '1950'
|
||||||
"""
|
"""
|
||||||
META = """
|
META = """
|
||||||
filename: null
|
external-document: null
|
||||||
extension: null
|
|
||||||
notes: []
|
notes: []
|
||||||
path: null
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@ -100,3 +98,22 @@ class TestSaveLoad(unittest.TestCase):
|
|||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.tmpdir)
|
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
|
import fixtures
|
||||||
from papers.repo import Repository, _str_incr, _to_suffix, BIB_DIR, META_DIR
|
from papers.repo import Repository, _str_incr, _to_suffix, BIB_DIR, META_DIR
|
||||||
|
from papers.paper import PaperInRepo
|
||||||
|
|
||||||
|
|
||||||
class TestCitekeyGeneration(unittest.TestCase):
|
class TestCitekeyGeneration(unittest.TestCase):
|
||||||
@ -29,7 +30,7 @@ class TestCitekeyGeneration(unittest.TestCase):
|
|||||||
self.assertEqual(c, 'Turing1950b')
|
self.assertEqual(c, 'Turing1950b')
|
||||||
|
|
||||||
|
|
||||||
class TestAddPaper(unittest.TestCase):
|
class TestRepo(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.tmpdir = tempfile.mkdtemp()
|
self.tmpdir = tempfile.mkdtemp()
|
||||||
@ -37,6 +38,12 @@ class TestAddPaper(unittest.TestCase):
|
|||||||
self.repo.init(self.tmpdir)
|
self.repo.init(self.tmpdir)
|
||||||
self.repo.add_paper(fixtures.turing1950)
|
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):
|
def test_raises_value_error_on_existing_key(self):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
self.repo.add_paper(fixtures.turing1950)
|
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,
|
self.assertTrue(os.path.exists(os.path.join(self.tmpdir, META_DIR,
|
||||||
'Turing1950.meta')))
|
'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