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.
Files changed (78) hide show
  1. {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/tests.yml +2 -3
  2. {papers_cli-2.18.0 → papers_cli-2.18.1}/PKG-INFO +1 -1
  3. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/adding-entries.md +19 -0
  4. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/features.md +1 -1
  5. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/__main__.py +2 -2
  6. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/_version.py +3 -3
  7. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/extract.py +1 -1
  8. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/PKG-INFO +1 -1
  9. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/scm_version.json +2 -2
  10. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_add.py +30 -0
  11. {papers_cli-2.18.0 → papers_cli-2.18.1}/.gitattributes +0 -0
  12. {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/FUNDING.yml +0 -0
  13. {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/docs.yml +0 -0
  14. {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/pypi.yml +0 -0
  15. {papers_cli-2.18.0 → papers_cli-2.18.1}/.github/workflows/release.yml +0 -0
  16. {papers_cli-2.18.0 → papers_cli-2.18.1}/.gitignore +0 -0
  17. {papers_cli-2.18.0 → papers_cli-2.18.1}/LICENSE +0 -0
  18. {papers_cli-2.18.0 → papers_cli-2.18.1}/README.md +0 -0
  19. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/comparison.md +0 -0
  20. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/configuration.md +0 -0
  21. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/git.md +0 -0
  22. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/index.md +0 -0
  23. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/installation.md +0 -0
  24. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/library-management.md +0 -0
  25. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/listing.md +0 -0
  26. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/quickstart.md +0 -0
  27. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/renaming.md +0 -0
  28. {papers_cli-2.18.0 → papers_cli-2.18.1}/docs/undo-redo.md +0 -0
  29. {papers_cli-2.18.0 → papers_cli-2.18.1}/mkdocs.yml +0 -0
  30. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/__init__.py +0 -0
  31. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/backup.py +0 -0
  32. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/bib.py +0 -0
  33. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/config.py +0 -0
  34. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/duplicate.py +0 -0
  35. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/encoding.py +0 -0
  36. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/entries.py +0 -0
  37. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/filename.py +0 -0
  38. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/install.py +0 -0
  39. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/latexenc.py +0 -0
  40. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers/utils.py +0 -0
  41. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/SOURCES.txt +0 -0
  42. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/dependency_links.txt +0 -0
  43. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/entry_points.txt +0 -0
  44. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/requires.txt +0 -0
  45. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/scm_file_list.json +0 -0
  46. {papers_cli-2.18.0 → papers_cli-2.18.1}/papers_cli.egg-info/top_level.txt +0 -0
  47. {papers_cli-2.18.0 → papers_cli-2.18.1}/pyproject.toml +0 -0
  48. {papers_cli-2.18.0 → papers_cli-2.18.1}/requirements.txt +0 -0
  49. {papers_cli-2.18.0 → papers_cli-2.18.1}/scripts/README.md +0 -0
  50. {papers_cli-2.18.0 → papers_cli-2.18.1}/scripts/benchmark_bibtexparser_load.py +0 -0
  51. {papers_cli-2.18.0 → papers_cli-2.18.1}/scripts/generate_dummy_bib.py +0 -0
  52. {papers_cli-2.18.0 → papers_cli-2.18.1}/setup.cfg +0 -0
  53. {papers_cli-2.18.0 → papers_cli-2.18.1}/setup.py +0 -0
  54. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/__init__.py +0 -0
  55. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/common.py +0 -0
  56. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/config.py +0 -0
  57. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/download.py +0 -0
  58. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/.gitignore +0 -0
  59. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/bg-8-515-2011.pdf +0 -0
  60. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/bg-8-515-2011.txt +0 -0
  61. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/esd-4-11-2013-supplement.pdf +0 -0
  62. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/downloadedpapers/esd-4-11-2013.pdf +0 -0
  63. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_backup_dirs.py +0 -0
  64. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_bib_unit.py +0 -0
  65. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_biblio.py +0 -0
  66. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_check.py +0 -0
  67. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_config_unit.py +0 -0
  68. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_duplicates.py +0 -0
  69. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_encoding.py +0 -0
  70. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_extract.py +0 -0
  71. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_extract_unit.py +0 -0
  72. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_filecheck.py +0 -0
  73. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_filename_unit.py +0 -0
  74. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_install.py +0 -0
  75. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_latexenc.py +0 -0
  76. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_list.py +0 -0
  77. {papers_cli-2.18.0 → papers_cli-2.18.1}/tests/test_undo.py +0 -0
  78. {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
- python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t" ]
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: papers-cli
3
- Version: 2.18.0
3
+ Version: 2.18.1
4
4
  Summary: utilities to keep your PDF library organized
5
5
  Author-email: Mahé Perrette <mahe.perrette@gmail.com>
6
6
  License: MIT
@@ -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.0'
22
- __version_tuple__ = version_tuple = (2, 18, 0)
21
+ __version__ = version = '2.18.1'
22
+ __version_tuple__ = version_tuple = (2, 18, 1)
23
23
 
24
- __commit_id__ = commit_id = 'g278a27c01'
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 (pass the DOI explicitly with --doi)')
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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: papers-cli
3
- Version: 2.18.0
3
+ Version: 2.18.1
4
4
  Summary: utilities to keep your PDF library organized
5
5
  Author-email: Mahé Perrette <mahe.perrette@gmail.com>
6
6
  License: MIT
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "2.18.0",
2
+ "tag": "2.18.1",
3
3
  "distance": 0,
4
- "node": "g278a27c0165766a31c0653163d2cd7032ce50385",
4
+ "node": "g0c4d92d882c38efd7f126f4edeadad0266f7f4b6",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-10-20"
@@ -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