papers-cli 2.18.0__tar.gz → 2.18.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/tests.yml +2 -3
- {papers_cli-2.18.0 → papers_cli-2.18.1}/PKG-INFO +1 -1
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/adding-entries.md +19 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/features.md +1 -1
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/__main__.py +2 -2
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/_version.py +3 -3
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/extract.py +1 -1
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/PKG-INFO +1 -1
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/scm_version.json +2 -2
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_add.py +30 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.gitattributes +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/FUNDING.yml +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/docs.yml +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/pypi.yml +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/release.yml +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/.gitignore +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/LICENSE +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/README.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/comparison.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/configuration.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/git.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/index.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/installation.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/library-management.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/listing.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/quickstart.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/renaming.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/undo-redo.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/mkdocs.yml +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/__init__.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/backup.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/bib.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/config.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/duplicate.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/encoding.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/entries.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/filename.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/install.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/latexenc.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/utils.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/SOURCES.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/dependency_links.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/entry_points.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/requires.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/scm_file_list.json +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/top_level.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/pyproject.toml +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/requirements.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/scripts/README.md +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/scripts/benchmark_bibtexparser_load.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/scripts/generate_dummy_bib.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/setup.cfg +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/setup.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/__init__.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/common.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/config.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/download.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/.gitignore +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/bg-8-515-2011.pdf +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/bg-8-515-2011.txt +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/esd-4-11-2013-supplement.pdf +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/esd-4-11-2013.pdf +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_backup_dirs.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_bib_unit.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_biblio.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_check.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_config_unit.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_duplicates.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_encoding.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_extract.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_extract_unit.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_filecheck.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_filename_unit.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_install.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_latexenc.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_list.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_undo.py +0 -0
- {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_utils.py +0 -0
|
@@ -8,12 +8,11 @@ jobs:
|
|
|
8
8
|
build:
|
|
9
9
|
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
|
-
# 3.15t is allowed to fail: PyMuPDF does not support it yet
|
|
12
|
-
continue-on-error: ${{ matrix.python-version == '3.15t' }}
|
|
13
11
|
strategy:
|
|
14
12
|
fail-fast: false
|
|
15
13
|
matrix:
|
|
16
|
-
|
|
14
|
+
# 3.15t: add when PyMuPDF supports it (https://github.com/pymupdf/PyMuPDF/issues/5170, #113)
|
|
15
|
+
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15" ]
|
|
17
16
|
|
|
18
17
|
steps:
|
|
19
18
|
- uses: actions/checkout@v6
|
|
@@ -46,6 +46,25 @@ where, above, the `papers_test` directory contains a few PDF files. For each
|
|
|
46
46
|
PDF, `papers` will attempt to extract the metadata and add the relevant file to
|
|
47
47
|
the bibliography, and rename files into the files directory.
|
|
48
48
|
|
|
49
|
+
The metadata of a PDF are found as follows:
|
|
50
|
+
|
|
51
|
+
1. a DOI in the PDF metadata is used as is;
|
|
52
|
+
2. otherwise, the DOIs printed in the text (first pages, and the last page,
|
|
53
|
+
where some publishers add a cover page) are looked up in turn, and the
|
|
54
|
+
first one whose title appears in the first pages is used: this skips the
|
|
55
|
+
DOIs of cited papers;
|
|
56
|
+
3. otherwise, a crossref search on the text of the first pages, whose result
|
|
57
|
+
is also accepted only if its title appears in the text.
|
|
58
|
+
|
|
59
|
+
If none matches, the PDF is not added: pass its DOI with `--doi` (see below),
|
|
60
|
+
or, for a reference without DOI (older papers, books, reports...), describe it
|
|
61
|
+
and attach the PDF:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
papers add --title "Self-consistent equilibrium ocean tides" --author "Agnew, Duncan C. and Farrell, W. E." \
|
|
65
|
+
--year 1978 --journal "Geophysical Journal International" --attachment agnew1978.pdf --rename
|
|
66
|
+
```
|
|
67
|
+
|
|
49
68
|
## Add an entry from its DOI
|
|
50
69
|
|
|
51
70
|
If you already know the DOI of a PDF, and don't want to gamble the fulltext
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Current features
|
|
4
4
|
|
|
5
5
|
- parse PDF to extract DOI
|
|
6
|
-
- fetch bibtex entry from DOI (using crossref API)
|
|
6
|
+
- fetch bibtex entry from DOI (using crossref API, or doi.org for DOIs registered elsewhere, e.g. DataCite)
|
|
7
7
|
- fetch bibtex entry by fulltext search (using crossref API or google scholar)
|
|
8
8
|
- create and maintain bibtex file
|
|
9
9
|
- add entry as PDF (`papers add ...`)
|
|
@@ -19,7 +19,7 @@ from papers.encoding import parse_file, format_file, family_names, format_entrie
|
|
|
19
19
|
from papers.config import (bcolors, Config, search_config, CONFIG_FILE, CONFIG_FILE_LOCAL,
|
|
20
20
|
DATA_DIR, CONFIG_FILE_LEGACY, CONFIG_FILE_LEGACY_XDG)
|
|
21
21
|
from papers.duplicate import list_duplicates, list_uniques, edit_entries, title_id
|
|
22
|
-
from papers.entries import get_entry_val, entry_content_equal
|
|
22
|
+
from papers.entries import get_entry_val, entry_content_equal, entry_from_dict
|
|
23
23
|
from papers.bib import (Biblio, FUZZY_RATIO, DEFAULT_SIMILARITY, entry_filecheck,
|
|
24
24
|
backupfile as backupfile_func, isvalidkey, DuplicateKeyError, clean_filesdir,
|
|
25
25
|
are_duplicates, download_url, get_biblio, scan_dir_walk)
|
|
@@ -329,7 +329,7 @@ def addcmd(parser, o, config):
|
|
|
329
329
|
metadata = edit_entries(metadata)
|
|
330
330
|
o.edit = False
|
|
331
331
|
|
|
332
|
-
entries.extend( biblio.insert_entry(metadata, **kw) )
|
|
332
|
+
entries.extend( biblio.insert_entry(entry_from_dict(metadata), rename=o.rename, copy=o.copy, **kw) )
|
|
333
333
|
|
|
334
334
|
|
|
335
335
|
# several PDFs: fetch their metadata concurrently first
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.18.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 18,
|
|
21
|
+
__version__ = version = '2.18.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 18, 1)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g0c4d92d88'
|
|
@@ -574,7 +574,7 @@ def extract_txt_metadata(txt, search_doi=True, search_fulltext=False, max_query_
|
|
|
574
574
|
return bibtex
|
|
575
575
|
logger.warning(f'fulltext query: title not found in the text: {title[:100]}')
|
|
576
576
|
|
|
577
|
-
raise ValueError('failed to extract metadata
|
|
577
|
+
raise ValueError('failed to extract metadata: pass the DOI with --doi, or, without DOI, add the entry with --title, --author, --year... and the PDF with --attachment')
|
|
578
578
|
|
|
579
579
|
|
|
580
580
|
def _metadata_from_pdf_contents(metadata_doi, read_text, search_doi=True, search_fulltext=True, **kw):
|
|
@@ -625,3 +625,33 @@ class TestAddDuplicateKeepsExistingKey(BibTest):
|
|
|
625
625
|
paperscmd(f'add {self.otherbib} --bibtex {self.mybib} -u -m a')
|
|
626
626
|
bib = Biblio.load(self.mybib, '')
|
|
627
627
|
self.assertEqual(sorted(e['ID'] for e in bib.entries), ['Perrette2013ESD', 'perrette_landerer2013'])
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
class TestAddWithoutDoi(unittest.TestCase):
|
|
631
|
+
"""an entry described on the command line (e.g. an old paper without DOI),
|
|
632
|
+
with its PDF attached"""
|
|
633
|
+
|
|
634
|
+
def setUp(self):
|
|
635
|
+
self.tmp = tempfile.TemporaryDirectory()
|
|
636
|
+
self.mybib = os.path.join(self.tmp.name, 'papers.bib')
|
|
637
|
+
self.filesdir = os.path.join(self.tmp.name, 'files')
|
|
638
|
+
self.pdf = os.path.join(self.tmp.name, 'old paper.pdf')
|
|
639
|
+
open(self.mybib, 'w').write('')
|
|
640
|
+
open(self.pdf, 'w').write('not really a pdf')
|
|
641
|
+
|
|
642
|
+
def tearDown(self):
|
|
643
|
+
self.tmp.cleanup()
|
|
644
|
+
|
|
645
|
+
def test_add_metadata_and_attachment(self):
|
|
646
|
+
paperscmd(f'add --bibtex {self.mybib} --filesdir {self.filesdir} --rename '
|
|
647
|
+
f'--title "Self-consistent equilibrium ocean tides" --author "Agnew, Duncan C. and Farrell, W. E." '
|
|
648
|
+
f'--year 1978 --attachment "{self.pdf}"')
|
|
649
|
+
bib = Biblio.load(self.mybib, self.filesdir)
|
|
650
|
+
self.assertEqual(len(bib.entries), 1)
|
|
651
|
+
e = bib.entries[0]
|
|
652
|
+
self.assertEqual(e['title'], 'Self-consistent equilibrium ocean tides')
|
|
653
|
+
self.assertEqual(e['year'], '1978')
|
|
654
|
+
files = bib.get_files(e)
|
|
655
|
+
self.assertEqual(len(files), 1)
|
|
656
|
+
self.assertTrue(os.path.abspath(files[0]).startswith(self.filesdir)) # --rename moved it
|
|
657
|
+
self.assertFalse(os.path.exists(self.pdf))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|