papers-cli 2.17__tar.gz → 2.17.2__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.17 → papers_cli-2.17.2}/PKG-INFO +1 -1
- papers_cli-2.17.2/docs/installation.md +47 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/__main__.py +35 -5
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/_version.py +3 -3
- {papers_cli-2.17 → papers_cli-2.17.2}/papers_cli.egg-info/PKG-INFO +1 -1
- {papers_cli-2.17 → papers_cli-2.17.2}/papers_cli.egg-info/entry_points.txt +1 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/pyproject.toml +7 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_list.py +41 -1
- papers_cli-2.17/docs/installation.md +0 -29
- {papers_cli-2.17 → papers_cli-2.17.2}/.gitattributes +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/.github/FUNDING.yml +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/.github/workflows/docs.yml +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/.github/workflows/pypi.yml +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/.github/workflows/release.yml +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/.github/workflows/tests.yml +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/.gitignore +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/LICENSE +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/README.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/adding-entries.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/comparison.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/configuration.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/features.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/git.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/index.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/library-management.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/listing.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/quickstart.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/renaming.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/docs/undo-redo.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/mkdocs.yml +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/__init__.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/backup.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/bib.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/config.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/duplicate.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/encoding.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/entries.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/extract.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/filename.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/install.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/latexenc.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers/utils.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers_cli.egg-info/SOURCES.txt +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers_cli.egg-info/dependency_links.txt +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers_cli.egg-info/requires.txt +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/papers_cli.egg-info/top_level.txt +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/requirements.txt +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/scripts/README.md +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/scripts/benchmark_bibtexparser_load.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/scripts/generate_dummy_bib.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/setup.cfg +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/setup.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/__init__.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/common.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/config.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/download.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/downloadedpapers/.gitignore +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/downloadedpapers/bg-8-515-2011.pdf +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/downloadedpapers/bg-8-515-2011.txt +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/downloadedpapers/esd-4-11-2013-supplement.pdf +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/downloadedpapers/esd-4-11-2013.pdf +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_add.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_backup_dirs.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_bib_unit.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_biblio.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_check.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_config_unit.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_duplicates.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_encoding.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_extract.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_extract_unit.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_filecheck.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_filename_unit.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_install.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_latexenc.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_undo.py +0 -0
- {papers_cli-2.17 → papers_cli-2.17.2}/tests/test_utils.py +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
## Install papers
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install papers-cli
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Note there is another project registered on PyPI as `papers`, hence
|
|
10
|
+
`papers-cli` for command-line-interface. The installed command is still
|
|
11
|
+
`papers`.
|
|
12
|
+
|
|
13
|
+
## Name clash with GNOME Papers
|
|
14
|
+
|
|
15
|
+
The [GNOME Papers](https://gitlab.gnome.org/GNOME/papers) document viewer
|
|
16
|
+
(the default viewer on recent GNOME desktops) also installs a `papers`
|
|
17
|
+
command; with both installed, whichever comes first in `$PATH` wins. Two
|
|
18
|
+
mitigations are built in:
|
|
19
|
+
|
|
20
|
+
- The package also installs the command under the unambiguous name
|
|
21
|
+
`papers-cli` — call that, or set a shell alias (e.g.
|
|
22
|
+
`alias papers=papers-cli`), on systems where the names collide.
|
|
23
|
+
- Because this command may mask GNOME Papers, `papers somefile.pdf` (a plain
|
|
24
|
+
existing file instead of a subcommand) opens the file with the system's
|
|
25
|
+
default viewer rather than erroring — which on a GNOME desktop typically
|
|
26
|
+
launches GNOME Papers itself, so the viewer keeps working for the common
|
|
27
|
+
case. Subcommand names always take precedence (`papers ./list` opens a
|
|
28
|
+
file named `list`; `papers list` lists your library), and viewer-specific
|
|
29
|
+
flags are not forwarded — call the viewer's binary directly for those.
|
|
30
|
+
|
|
31
|
+
## Dependencies
|
|
32
|
+
|
|
33
|
+
- python 3.9+
|
|
34
|
+
- [PyMuPDF](https://github.com/pymupdf/PyMuPDF) (preferred) or
|
|
35
|
+
[poppler-utils](https://en.wikipedia.org/wiki/Poppler_(software))
|
|
36
|
+
(only `pdftotext`; deprecated): convert PDF to text for parsing
|
|
37
|
+
- [bibtexparser](https://bibtexparser.readthedocs.io): parse bibtex files
|
|
38
|
+
- [crossrefapi](https://github.com/fabiobatalha/crossrefapi): make polite
|
|
39
|
+
requests to the crossref API
|
|
40
|
+
- [scholarly](https://github.com/OrganicIrradiation/scholarly): interface for
|
|
41
|
+
google scholar
|
|
42
|
+
- [rapidfuzz](https://github.com/rhasspy/rapidfuzz): calculate score to sort
|
|
43
|
+
crossref requests
|
|
44
|
+
- [unidecode](https://github.com/avian2/unidecode): replace unicode with ascii
|
|
45
|
+
equivalent
|
|
46
|
+
|
|
47
|
+
The Python dependencies are installed automatically with `pip`.
|
|
@@ -731,9 +731,21 @@ def listcmd(parser, o, config):
|
|
|
731
731
|
|
|
732
732
|
|
|
733
733
|
def opencmd(parser, o, config):
|
|
734
|
-
biblio =
|
|
735
|
-
entries_by_key = {
|
|
734
|
+
biblio = None
|
|
735
|
+
entries_by_key = {}
|
|
736
736
|
for key in o.key:
|
|
737
|
+
# an existing file is opened directly with the system viewer; anything
|
|
738
|
+
# else is looked up as an entry key in the bibliography
|
|
739
|
+
if os.path.isfile(key):
|
|
740
|
+
logger.info(f"opening {key} ...")
|
|
741
|
+
view_pdf(key)
|
|
742
|
+
continue
|
|
743
|
+
if biblio is None:
|
|
744
|
+
try:
|
|
745
|
+
biblio = get_biblio(config)
|
|
746
|
+
except ValueError:
|
|
747
|
+
raise PapersExit(f"'{key}' is not an existing file, and no bibliography is configured to look it up as a key")
|
|
748
|
+
entries_by_key = {biblio.key(e): e for e in biblio.entries}
|
|
737
749
|
e = entries_by_key.get(key.lower())
|
|
738
750
|
if e is None:
|
|
739
751
|
logger.error(f'no entry found with key: {key}')
|
|
@@ -1040,8 +1052,8 @@ def get_parser(config=None):
|
|
|
1040
1052
|
|
|
1041
1053
|
# open
|
|
1042
1054
|
# ====
|
|
1043
|
-
openp = subparsers.add_parser('open', description='open
|
|
1044
|
-
openp.add_argument('key', nargs='+', help='entry key(s)
|
|
1055
|
+
openp = subparsers.add_parser('open', description='open entry attachments or files with the system viewer', parents=[cfg])
|
|
1056
|
+
openp.add_argument('key', nargs='+', help='entry key(s) (case-insensitive), or existing file path(s) to open directly')
|
|
1045
1057
|
|
|
1046
1058
|
# doi
|
|
1047
1059
|
# ===
|
|
@@ -1125,6 +1137,22 @@ def main(args=None):
|
|
|
1125
1137
|
|
|
1126
1138
|
parser, subparsers = get_parser(config)
|
|
1127
1139
|
|
|
1140
|
+
# viewer passthrough (#107): this command often masks the GNOME Papers
|
|
1141
|
+
# document viewer in $PATH, so `papers somefile.pdf` opens the file(s)
|
|
1142
|
+
# with the system viewer instead of erroring. xdg-open resolves the
|
|
1143
|
+
# handler via desktop entries, not $PATH, so this typically launches the
|
|
1144
|
+
# masked viewer itself. Subcommand names always take precedence, and any
|
|
1145
|
+
# flag disables the passthrough (it cannot be meant for this tool).
|
|
1146
|
+
argv = sys.argv[1:]
|
|
1147
|
+
if argv and all(not a.startswith('-') for a in argv) \
|
|
1148
|
+
and argv[0] not in subparsers.choices \
|
|
1149
|
+
and all(os.path.isfile(a) for a in argv):
|
|
1150
|
+
for f in argv:
|
|
1151
|
+
print(f"papers-cli: opening {f!r} with the system viewer "
|
|
1152
|
+
f"(see `papers --help` for the bibliography tool)", file=sys.stderr)
|
|
1153
|
+
view_pdf(f)
|
|
1154
|
+
return
|
|
1155
|
+
|
|
1128
1156
|
o, args = parser.parse_known_args(args)
|
|
1129
1157
|
|
|
1130
1158
|
if o.version:
|
|
@@ -1167,7 +1195,9 @@ def main(args=None):
|
|
|
1167
1195
|
elif o.cmd == 'list':
|
|
1168
1196
|
check_install(subp, o, config) and listcmd(subp, o, config)
|
|
1169
1197
|
elif o.cmd == 'open':
|
|
1170
|
-
|
|
1198
|
+
# no install required when opening plain files; opencmd reports the
|
|
1199
|
+
# missing bibliography itself when an argument must be looked up as a key
|
|
1200
|
+
opencmd(subp, o, config)
|
|
1171
1201
|
elif o.cmd == 'undo':
|
|
1172
1202
|
check_install(subp, o, config) and undocmd(subp, o, config)
|
|
1173
1203
|
elif o.cmd == 'redo':
|
|
@@ -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.17'
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 17)
|
|
21
|
+
__version__ = version = '2.17.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 17, 2)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g7e17d470e'
|
|
@@ -43,11 +43,18 @@ docs = [
|
|
|
43
43
|
homepage = "https://github.com/perrette/papers"
|
|
44
44
|
Documentation = "https://perrette.github.io/papers/"
|
|
45
45
|
|
|
46
|
+
[tool.setuptools]
|
|
47
|
+
# explicit: auto-discovery fails on stray top-level dirs (site/, notes/...)
|
|
48
|
+
packages = ["papers"]
|
|
49
|
+
|
|
46
50
|
[tool.setuptools_scm]
|
|
47
51
|
write_to = "papers/_version.py"
|
|
48
52
|
|
|
49
53
|
[project.scripts]
|
|
50
54
|
papers = "papers.__main__:main_clean_exit"
|
|
55
|
+
# unambiguous alternative for systems where `papers` clashes with the
|
|
56
|
+
# GNOME Papers document viewer (issue #107)
|
|
57
|
+
papers-cli = "papers.__main__:main_clean_exit"
|
|
51
58
|
|
|
52
59
|
[tool.tox]
|
|
53
60
|
# Tox (https://tox.readthedocs.io/) is a tool for running tests
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import bibtexparser
|
|
2
|
-
from tests.common import LocalInstallTest, Biblio, tempfile
|
|
2
|
+
from tests.common import LocalInstallTest, BaseTest, Biblio, tempfile
|
|
3
3
|
from papers.utils import strip_all
|
|
4
4
|
|
|
5
5
|
bibtex = """@article{Perrette_2011,
|
|
@@ -246,3 +246,43 @@ class OpenCmdTest(LocalInstallTest):
|
|
|
246
246
|
|
|
247
247
|
def test_open_unknown_key(self):
|
|
248
248
|
self.papers('open NoSuchKey') # logs an error, does not crash
|
|
249
|
+
|
|
250
|
+
def test_open_file_path(self):
|
|
251
|
+
# `papers open` also accepts existing file paths directly
|
|
252
|
+
from unittest.mock import patch
|
|
253
|
+
f = self._path('direct.pdf')
|
|
254
|
+
open(f, 'w').write('x')
|
|
255
|
+
with patch('papers.__main__.view_pdf') as viewer:
|
|
256
|
+
self.papers(f'open {f}')
|
|
257
|
+
viewer.assert_called_once_with(f)
|
|
258
|
+
|
|
259
|
+
def test_bare_file_argument_opens_viewer(self):
|
|
260
|
+
# `papers somefile.pdf` behaves like the (possibly masked) document
|
|
261
|
+
# viewer: the file is opened with the system viewer (issue #107)
|
|
262
|
+
from unittest.mock import patch
|
|
263
|
+
f = self._path('direct.pdf')
|
|
264
|
+
open(f, 'w').write('x')
|
|
265
|
+
with patch('papers.__main__.view_pdf') as viewer:
|
|
266
|
+
self.papers(f'{f}')
|
|
267
|
+
viewer.assert_called_once_with(f)
|
|
268
|
+
|
|
269
|
+
def test_subcommand_wins_over_file(self):
|
|
270
|
+
# a file named like a subcommand does not hijack the CLI
|
|
271
|
+
from unittest.mock import patch
|
|
272
|
+
open(self._path('status'), 'w').write('x')
|
|
273
|
+
with patch('papers.__main__.view_pdf') as viewer:
|
|
274
|
+
self.papers('status')
|
|
275
|
+
viewer.assert_not_called()
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class ViewerPassthroughNoInstallTest(BaseTest):
|
|
279
|
+
anotherbib_content = None
|
|
280
|
+
|
|
281
|
+
def test_bare_file_argument_without_install(self):
|
|
282
|
+
# the viewer passthrough must work without any papers install
|
|
283
|
+
from unittest.mock import patch
|
|
284
|
+
f = self._path('doc.pdf')
|
|
285
|
+
open(f, 'w').write('x')
|
|
286
|
+
with patch('papers.__main__.view_pdf') as viewer:
|
|
287
|
+
self.papers(f'{f}')
|
|
288
|
+
viewer.assert_called_once_with(f)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
# Installation
|
|
2
|
-
|
|
3
|
-
## Install papers
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
pip install papers-cli
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Note there is another project registered on PyPI as `papers`, hence
|
|
10
|
-
`papers-cli` for command-line-interface. The installed command is still
|
|
11
|
-
`papers`.
|
|
12
|
-
|
|
13
|
-
## Dependencies
|
|
14
|
-
|
|
15
|
-
- python 3.9+
|
|
16
|
-
- [PyMuPDF](https://github.com/pymupdf/PyMuPDF) (preferred) or
|
|
17
|
-
[poppler-utils](https://en.wikipedia.org/wiki/Poppler_(software))
|
|
18
|
-
(only `pdftotext`; deprecated): convert PDF to text for parsing
|
|
19
|
-
- [bibtexparser](https://bibtexparser.readthedocs.io): parse bibtex files
|
|
20
|
-
- [crossrefapi](https://github.com/fabiobatalha/crossrefapi): make polite
|
|
21
|
-
requests to the crossref API
|
|
22
|
-
- [scholarly](https://github.com/OrganicIrradiation/scholarly): interface for
|
|
23
|
-
google scholar
|
|
24
|
-
- [rapidfuzz](https://github.com/rhasspy/rapidfuzz): calculate score to sort
|
|
25
|
-
crossref requests
|
|
26
|
-
- [unidecode](https://github.com/avian2/unidecode): replace unicode with ascii
|
|
27
|
-
equivalent
|
|
28
|
-
|
|
29
|
-
The Python dependencies are installed automatically with `pip`.
|
|
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
|