papers-cli 2.17.4__tar.gz → 2.17.5__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.4 → papers_cli-2.17.5}/PKG-INFO +7 -1
- {papers_cli-2.17.4 → papers_cli-2.17.5}/README.md +6 -0
- papers_cli-2.17.5/docs/adding-entries.md +93 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/quickstart.md +3 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/__main__.py +63 -22
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/_version.py +3 -3
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/backup.py +9 -1
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/bib.py +16 -4
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/extract.py +198 -41
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/PKG-INFO +7 -1
- papers_cli-2.17.5/papers_cli.egg-info/scm_version.json +8 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_add.py +113 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_backup_dirs.py +85 -1
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_duplicates.py +2 -2
- papers_cli-2.17.5/tests/test_extract_unit.py +430 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_list.py +7 -0
- papers_cli-2.17.4/docs/adding-entries.md +0 -61
- papers_cli-2.17.4/papers_cli.egg-info/scm_version.json +0 -8
- papers_cli-2.17.4/tests/test_extract_unit.py +0 -192
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.gitattributes +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.github/FUNDING.yml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.github/workflows/docs.yml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.github/workflows/pypi.yml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.github/workflows/release.yml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.github/workflows/tests.yml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/.gitignore +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/LICENSE +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/comparison.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/configuration.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/features.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/git.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/index.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/installation.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/library-management.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/listing.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/renaming.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/docs/undo-redo.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/mkdocs.yml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/__init__.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/config.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/duplicate.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/encoding.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/entries.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/filename.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/install.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/latexenc.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers/utils.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/SOURCES.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/dependency_links.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/entry_points.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/requires.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/scm_file_list.json +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/papers_cli.egg-info/top_level.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/pyproject.toml +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/requirements.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/scripts/README.md +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/scripts/benchmark_bibtexparser_load.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/scripts/generate_dummy_bib.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/setup.cfg +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/setup.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/__init__.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/common.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/config.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/download.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/downloadedpapers/.gitignore +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/downloadedpapers/bg-8-515-2011.pdf +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/downloadedpapers/bg-8-515-2011.txt +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/downloadedpapers/esd-4-11-2013-supplement.pdf +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/downloadedpapers/esd-4-11-2013.pdf +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_bib_unit.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_biblio.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_check.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_config_unit.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_encoding.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_extract.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_filecheck.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_filename_unit.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_install.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_latexenc.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_undo.py +0 -0
- {papers_cli-2.17.4 → papers_cli-2.17.5}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: papers-cli
|
|
3
|
-
Version: 2.17.
|
|
3
|
+
Version: 2.17.5
|
|
4
4
|
Summary: utilities to keep your PDF library organized
|
|
5
5
|
Author-email: Mahé Perrette <mahe.perrette@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -91,6 +91,12 @@ papers add esd-4-11-2013.pdf --rename --copy --bibtex papers.bib --filesdir file
|
|
|
91
91
|
papers list perrette scaling approach sea level
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
Without `--rename` (`-r`) the PDF is linked where it is: the entry points to
|
|
95
|
+
its current location and nothing is copied into the files directory. `--rename`
|
|
96
|
+
moves it into `--filesdir` under a name made from the name template, and
|
|
97
|
+
`--copy` (`-c`) makes a copy instead of moving (it has no effect without
|
|
98
|
+
`--rename`).
|
|
99
|
+
|
|
94
100
|
See the [quickstart](https://perrette.github.io/papers/quickstart/) for a full
|
|
95
101
|
walkthrough.
|
|
96
102
|
|
|
@@ -63,6 +63,12 @@ papers add esd-4-11-2013.pdf --rename --copy --bibtex papers.bib --filesdir file
|
|
|
63
63
|
papers list perrette scaling approach sea level
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
Without `--rename` (`-r`) the PDF is linked where it is: the entry points to
|
|
67
|
+
its current location and nothing is copied into the files directory. `--rename`
|
|
68
|
+
moves it into `--filesdir` under a name made from the name template, and
|
|
69
|
+
`--copy` (`-c`) makes a copy instead of moving (it has no effect without
|
|
70
|
+
`--rename`).
|
|
71
|
+
|
|
66
72
|
See the [quickstart](https://perrette.github.io/papers/quickstart/) for a full
|
|
67
73
|
walkthrough.
|
|
68
74
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Adding entries
|
|
2
|
+
|
|
3
|
+
The `papers add` command adds entries to your library, with or without a PDF
|
|
4
|
+
attachment.
|
|
5
|
+
|
|
6
|
+
## Add a PDF (extract metadata automatically)
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
$> papers add esd-4-11-2013.pdf --rename --copy --bibtex papers.bib --filesdir files --info
|
|
10
|
+
INFO:papers:found doi:10.5194/esd-4-11-2013
|
|
11
|
+
INFO:papers:new entry: perrette_landerer2013
|
|
12
|
+
INFO:papers:mv /home/perrette/playground/papers/esd-4-11-2013.pdf files/perrette_et_al_2013_a-scaling-approach-to-project-regional-sea-level-rise-and-its-uncertainties.pdf
|
|
13
|
+
INFO:papers:renamed file(s): 1
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
That is equivalent to doing:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
papers extract esd-4-11-2013.pdf > entry.bib
|
|
20
|
+
papers add entry.bib --bibtex papers.bib --attachment esd-4-11-2013.pdf --rename --copy
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Without `--rename` (`-r`) the PDF is linked where it is: the `file` field
|
|
24
|
+
points to its current location and nothing is moved or copied into the files
|
|
25
|
+
directory. `--rename` moves the file into `--filesdir` under a name made from
|
|
26
|
+
the name template, and `--copy` (`-c`) makes a copy there instead of moving
|
|
27
|
+
the original (it has no effect without `--rename`). The same applies to the
|
|
28
|
+
files linked from the entries of a bibtex file added with `papers add
|
|
29
|
+
other.bib`: their paths are read relative to that bibtex and stored so that
|
|
30
|
+
they remain valid from your own bibtex (absolute, or relative to it, according
|
|
31
|
+
to `--absolute-paths`/`--relative-paths` or the installed setting); with
|
|
32
|
+
`--rename` they are moved (or copied with `--copy`) into the files directory.
|
|
33
|
+
|
|
34
|
+
See [Renaming files and keys](renaming.md) for how to specify file naming
|
|
35
|
+
patterns.
|
|
36
|
+
|
|
37
|
+
## Add a whole directory of PDFs
|
|
38
|
+
|
|
39
|
+
It is possible to do this on a full directory of files, recursively:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
papers add --rename --recursive /home/perette/playground/papers/papers_test
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
where, above, the `papers_test` directory contains a few PDF files. For each
|
|
46
|
+
PDF, `papers` will attempt to extract the metadata and add the relevant file to
|
|
47
|
+
the bibliography, and rename files into the files directory.
|
|
48
|
+
|
|
49
|
+
## Add an entry from its DOI
|
|
50
|
+
|
|
51
|
+
If you already know the DOI of a PDF, and don't want to gamble the fulltext
|
|
52
|
+
search and match, you can indicate it via `--doi`:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
papers add esd-4-11-2013.pdf --doi 10.5194/esd-4-11-2013 --bibtex papers.bib
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `add` command above also works without any PDF (create a bibtex entry
|
|
59
|
+
without file attachment):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
papers add --doi 10.5194/esd-4-11-2013 --bibtex papers.bib
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Add an entry without DOI from bibtex + PDF
|
|
66
|
+
|
|
67
|
+
Some old files don't have a DOI. The best approach is to add the entry from its
|
|
68
|
+
bibtex:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
papers add entry.bib --attachment esd-4-11-2013.pdf
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Duplicates and keys
|
|
75
|
+
|
|
76
|
+
Before inserting an entry, `papers add` looks for a duplicate in the library
|
|
77
|
+
(same DOI, or same authors and title). The `-m/--mode` option says what to do
|
|
78
|
+
when one is found: `i` (interactive, the default), `u` (update the existing
|
|
79
|
+
entry with the new entry's missing fields, existing values win), `U` (update
|
|
80
|
+
the existing entry with the new entry's values, new values win), `o`
|
|
81
|
+
(overwrite), `s` (skip the new entry), `a` (append it anyway), `r` (raise an
|
|
82
|
+
error).
|
|
83
|
+
|
|
84
|
+
Entries added from a bibtex file keep their own key, unless `-u/--update-key`
|
|
85
|
+
is passed, in which case the key is regenerated from the key template (see
|
|
86
|
+
[Renaming files and keys](renaming.md)). Entries extracted from a PDF or
|
|
87
|
+
fetched from a DOI always get a generated key.
|
|
88
|
+
|
|
89
|
+
With `-u/--update-key`, a duplicate is always merged under the key of the entry
|
|
90
|
+
already in the library, in every mode (`u`, `U`, `o`; with `a` the existing
|
|
91
|
+
entry keeps its key and the appended entry gets a fresh one). Without `-u`,
|
|
92
|
+
modes `u` and `s` keep the existing entry's key, while `U` and `o` take over
|
|
93
|
+
the new entry's key.
|
|
@@ -43,6 +43,9 @@ INFO:papers:renamed file(s): 1
|
|
|
43
43
|
(the `--info` argument asks for the above output information to be printed out
|
|
44
44
|
to the terminal)
|
|
45
45
|
|
|
46
|
+
Without `--rename` the PDF is linked where it is, and nothing is copied into
|
|
47
|
+
the files directory; `--copy` only applies together with `--rename`.
|
|
48
|
+
|
|
46
49
|
See [Adding entries](adding-entries.md) for the full range of ways to add
|
|
47
50
|
entries, and [Renaming files and keys](renaming.md) for how to specify file
|
|
48
51
|
naming patterns.
|
|
@@ -69,10 +69,14 @@ def savebib(biblio, config):
|
|
|
69
69
|
logger.info(f'Saving {config.bibtex}')
|
|
70
70
|
if biblio is not None:
|
|
71
71
|
biblio.save(config.bibtex)
|
|
72
|
-
if config.
|
|
73
|
-
|
|
72
|
+
if config.git:
|
|
73
|
+
# the backup comes last: a failure must not undo the work done above
|
|
74
|
+
try:
|
|
75
|
+
silent_backup_bib(biblio, config)
|
|
76
|
+
except Exception as error:
|
|
77
|
+
logger.error(f'the bibliography was saved, but its git backup failed: {error}')
|
|
74
78
|
else:
|
|
75
|
-
logger.debug(f'do not backup bib:
|
|
79
|
+
logger.debug(f'do not backup bib: git is off')
|
|
76
80
|
# if config.git:
|
|
77
81
|
# config.gitcommit()
|
|
78
82
|
|
|
@@ -177,11 +181,43 @@ def uninstallcmd(parser, o, config):
|
|
|
177
181
|
if os.path.exists(configfile):
|
|
178
182
|
uninstallcmd(parser, o, Config.load(configfile))
|
|
179
183
|
|
|
184
|
+
def config_for_bibtex(bibtex, config):
|
|
185
|
+
"""The configuration to use when --bibtex is passed on the command line.
|
|
186
|
+
|
|
187
|
+
If it is another library than the configured one, the local configuration
|
|
188
|
+
of that library (searched from the bibtex's directory upwards, as for the
|
|
189
|
+
current directory) applies: its files directory, git backup and formats.
|
|
190
|
+
Without one, the current configuration applies to the bibtex, except that
|
|
191
|
+
it is never written back to disk and the backup goes to a directory of
|
|
192
|
+
the bibtex's own.
|
|
193
|
+
"""
|
|
194
|
+
if config.bibtex and os.path.realpath(bibtex) == os.path.realpath(config.bibtex):
|
|
195
|
+
return config
|
|
196
|
+
|
|
197
|
+
configfile = search_config([CONFIG_FILE_LOCAL, os.path.join(".papers", "config.json")],
|
|
198
|
+
start_dir=os.path.dirname(os.path.abspath(bibtex)), default=None)
|
|
199
|
+
if configfile is not None:
|
|
200
|
+
other = Config.load(check_legacy_config(configfile))
|
|
201
|
+
if other.bibtex and os.path.realpath(other.bibtex) == os.path.realpath(bibtex):
|
|
202
|
+
logger.info(f'configuration of {bibtex}: {configfile}')
|
|
203
|
+
return other
|
|
204
|
+
|
|
205
|
+
logger.debug(f'{bibtex} has no configuration of its own: use {config.file} without saving it')
|
|
206
|
+
config = copy.copy(config)
|
|
207
|
+
config.file = None
|
|
208
|
+
if config.git:
|
|
209
|
+
from papers.backup import resolve_gitdir
|
|
210
|
+
config.gitdir = resolve_gitdir(bibtex)
|
|
211
|
+
return config
|
|
212
|
+
|
|
213
|
+
|
|
180
214
|
def check_install(parser, o, config, bibtex_must_exist=True):
|
|
181
215
|
"""
|
|
182
216
|
Given an option and config, checks to see if the install is done correctly on this filesystem.
|
|
217
|
+
Returns the configuration to use (see config_for_bibtex).
|
|
183
218
|
"""
|
|
184
219
|
if getattr(o, "bibtex", None) is not None:
|
|
220
|
+
config = config_for_bibtex(o.bibtex, config)
|
|
185
221
|
config.bibtex = o.bibtex
|
|
186
222
|
if getattr(o, "filesdir", None) is not None:
|
|
187
223
|
config.filesdir = o.filesdir
|
|
@@ -201,7 +237,7 @@ def check_install(parser, o, config, bibtex_must_exist=True):
|
|
|
201
237
|
raise PapersExit()
|
|
202
238
|
logger.info(f'bibtex: {config.bibtex!r}')
|
|
203
239
|
logger.info(f'filesdir: {config.filesdir!r}')
|
|
204
|
-
return
|
|
240
|
+
return config
|
|
205
241
|
|
|
206
242
|
|
|
207
243
|
def _print_biblio_diff(biblio_init, biblio, touched_entries, show_existing=False):
|
|
@@ -781,9 +817,9 @@ def get_parser(config=None):
|
|
|
781
817
|
|
|
782
818
|
cfg = argparse.ArgumentParser(add_help=False, parents=[loggingp])
|
|
783
819
|
grp = cfg.add_argument_group('config')
|
|
784
|
-
grp.add_argument('--filesdir', default=None,
|
|
820
|
+
grp.add_argument('--filesdir', default=None, type=file_uri_to_path,
|
|
785
821
|
help=f'files directory (default: {config.filesdir}')
|
|
786
|
-
grp.add_argument('--bibtex', default=None,
|
|
822
|
+
grp.add_argument('--bibtex', default=None, type=file_uri_to_path,
|
|
787
823
|
help=f'bibtex database (default: {config.bibtex}')
|
|
788
824
|
grp.add_argument('--dry-run', action='store_true',
|
|
789
825
|
help='no PDF renaming/copying, no bibtex writing on disk (for testing)')
|
|
@@ -878,7 +914,7 @@ def get_parser(config=None):
|
|
|
878
914
|
# ===
|
|
879
915
|
addp = subparsers.add_parser('add', description='add PDF(s) or bibtex(s) to library',
|
|
880
916
|
parents=[cfg, namefmt, keyfmt])
|
|
881
|
-
addp.add_argument('file', nargs='*', default=[])
|
|
917
|
+
addp.add_argument('file', nargs='*', default=[], type=file_uri_to_path)
|
|
882
918
|
# addp.add_argument('-f','--force', action='store_true', help='disable interactive')
|
|
883
919
|
|
|
884
920
|
grp = addp.add_argument_group('duplicate check')
|
|
@@ -918,12 +954,17 @@ def get_parser(config=None):
|
|
|
918
954
|
grp.add_argument('--no-query-fulltext', action='store_true', help='do not attempt to query fulltext in case doi query fails')
|
|
919
955
|
grp.add_argument('--scholar', action='store_true', help='use google scholar instead of crossref')
|
|
920
956
|
|
|
921
|
-
grp = addp.add_argument_group('attached files'
|
|
922
|
-
|
|
957
|
+
grp = addp.add_argument_group('attached files',
|
|
958
|
+
description='''Without -r/--rename, the PDF (and the files of a bibtex entry) are linked
|
|
959
|
+
where they are: the file field points to their current location and nothing is
|
|
960
|
+
moved or copied into the files directory. -r moves them into the files directory
|
|
961
|
+
(--filesdir) under a name made from the name template; with -c the original is
|
|
962
|
+
kept and a copy is made instead (-c has no effect without -r).''')
|
|
963
|
+
grp.add_argument('-a','--attachment', nargs='+', type=file_uri_to_path, help='attach these files to the entry (supplementary material)')
|
|
923
964
|
grp.add_argument('-r','--rename', action='store_true',
|
|
924
|
-
help='
|
|
965
|
+
help='move the files into the files directory, renamed according to the name template')
|
|
925
966
|
grp.add_argument('-c','--copy', action='store_true',
|
|
926
|
-
help='copy
|
|
967
|
+
help='with -r, copy the files instead of moving them')
|
|
927
968
|
|
|
928
969
|
grp = addp.add_argument_group('actions')
|
|
929
970
|
grp.add_argument('-e', '--edit', action='store_true', help='edit entry')
|
|
@@ -1048,7 +1089,7 @@ def get_parser(config=None):
|
|
|
1048
1089
|
grp.add_argument('-e', '--edit', action='store_true', help='interactive edit text file with entries, and re-insert them')
|
|
1049
1090
|
grp.add_argument('--fetch', action='store_true', help='fetch and fix metadata')
|
|
1050
1091
|
grp.add_argument('--add-keywords', '--add-tag', nargs='+', help='add keywords to the selected entries')
|
|
1051
|
-
grp.add_argument('--add-files', nargs='+', help='add files to the selected entries (only one entry must be listed)')
|
|
1092
|
+
grp.add_argument('--add-files', nargs='+', type=file_uri_to_path, help='add files to the selected entries (only one entry must be listed)')
|
|
1052
1093
|
grp.add_argument('--rename', action='store_true', help='rename file(s) of the listed entries into the files folder (also applies to files added via --add-files)')
|
|
1053
1094
|
grp.add_argument('--copy', action='store_true', help='in combination with --rename, keep a copy of the file(s) in their original location')
|
|
1054
1095
|
grp.add_argument('-o', '--open', action='store_true', help='open attachments (if any)')
|
|
@@ -1059,12 +1100,12 @@ def get_parser(config=None):
|
|
|
1059
1100
|
# open
|
|
1060
1101
|
# ====
|
|
1061
1102
|
openp = subparsers.add_parser('open', description='open entry attachments or files with the system viewer', parents=[cfg])
|
|
1062
|
-
openp.add_argument('key', nargs='+', help='entry key(s) (case-insensitive), or existing file path(s) to open directly')
|
|
1103
|
+
openp.add_argument('key', nargs='+', type=file_uri_to_path, help='entry key(s) (case-insensitive), or existing file path(s) to open directly')
|
|
1063
1104
|
|
|
1064
1105
|
# doi
|
|
1065
1106
|
# ===
|
|
1066
1107
|
doip = subparsers.add_parser('doi', description='parse DOI from PDF', parents=[loggingp])
|
|
1067
|
-
doip.add_argument('pdf')
|
|
1108
|
+
doip.add_argument('pdf', type=file_uri_to_path)
|
|
1068
1109
|
doip.add_argument('--image', action='store_true', help='convert to image and use tesseract instead of pdftotext')
|
|
1069
1110
|
|
|
1070
1111
|
# fetch
|
|
@@ -1076,7 +1117,7 @@ def get_parser(config=None):
|
|
|
1076
1117
|
# extract
|
|
1077
1118
|
# ========
|
|
1078
1119
|
extractp = subparsers.add_parser('extract', description='extract pdf metadata', parents=[loggingp])
|
|
1079
|
-
extractp.add_argument('pdf', nargs='+', help='one or several PDF files')
|
|
1120
|
+
extractp.add_argument('pdf', nargs='+', type=file_uri_to_path, help='one or several PDF files')
|
|
1080
1121
|
extractp.add_argument('--recursive', action='store_true', help='accept directories and scan them for PDF files')
|
|
1081
1122
|
extractp.add_argument('-n', '--word-count', type=int, default=200)
|
|
1082
1123
|
extractp.add_argument('--fulltext', action='store_true', help='fulltext only (otherwise DOI-based)')
|
|
@@ -1212,23 +1253,23 @@ def main(args=None):
|
|
|
1212
1253
|
uninstallcmd(subp, o, config)
|
|
1213
1254
|
print(config.status(verbose=True))
|
|
1214
1255
|
elif o.cmd == 'add':
|
|
1215
|
-
|
|
1256
|
+
addcmd(subp, o, check_install(subp, o, config))
|
|
1216
1257
|
elif o.cmd == 'check':
|
|
1217
|
-
|
|
1258
|
+
checkcmd(subp, o, check_install(subp, o, config))
|
|
1218
1259
|
elif o.cmd == 'filecheck':
|
|
1219
|
-
|
|
1260
|
+
filecheckcmd(subp, o, check_install(subp, o, config))
|
|
1220
1261
|
elif o.cmd == 'list':
|
|
1221
|
-
|
|
1262
|
+
listcmd(subp, o, check_install(subp, o, config))
|
|
1222
1263
|
elif o.cmd == 'open':
|
|
1223
1264
|
# no install required when opening plain files; opencmd reports the
|
|
1224
1265
|
# missing bibliography itself when an argument must be looked up as a key
|
|
1225
1266
|
opencmd(subp, o, config)
|
|
1226
1267
|
elif o.cmd == 'undo':
|
|
1227
|
-
|
|
1268
|
+
undocmd(subp, o, check_install(subp, o, config))
|
|
1228
1269
|
elif o.cmd == 'redo':
|
|
1229
|
-
|
|
1270
|
+
redocmd(subp, o, check_install(subp, o, config))
|
|
1230
1271
|
elif o.cmd == 'restore-backup':
|
|
1231
|
-
|
|
1272
|
+
restorecmd(subp, o, check_install(subp, o, config, bibtex_must_exist=False))
|
|
1232
1273
|
elif o.cmd == 'git':
|
|
1233
1274
|
if not installed:
|
|
1234
1275
|
subp.error('papers must be installed to use git command')
|
|
@@ -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.5'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 17, 5)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g6f089411a'
|
|
@@ -244,13 +244,21 @@ def backup_bib(biblio, config, message=None):
|
|
|
244
244
|
|
|
245
245
|
if not config.git:
|
|
246
246
|
raise PapersExit('cannot backup without --git enabled')
|
|
247
|
+
if not config.gitdir:
|
|
248
|
+
config.gitdir = resolve_gitdir(config.bibtex)
|
|
247
249
|
backupdir = Path(config.gitdir)
|
|
248
|
-
backupdir.mkdir(exist_ok=True)
|
|
250
|
+
backupdir.mkdir(parents=True, exist_ok=True)
|
|
249
251
|
|
|
250
252
|
# never mix the histories of two libraries in one backup directory
|
|
251
253
|
check_gitdir_ownership(config)
|
|
252
254
|
backupdir = Path(config.gitdir) # may have been re-allocated
|
|
253
255
|
|
|
256
|
+
# a backup directory that was never initialized (or removed since the install)
|
|
257
|
+
if not (backupdir / ".git").exists():
|
|
258
|
+
logger.info(f"initialize backup repository: {backupdir}")
|
|
259
|
+
run_git(config.gitdir, ["init"])
|
|
260
|
+
write_manifest(config.gitdir, config.bibtex)
|
|
261
|
+
|
|
254
262
|
# a snapshot made while undone must append to the full history
|
|
255
263
|
adopt_legacy_undone_state(config.gitdir)
|
|
256
264
|
|
|
@@ -463,7 +463,13 @@ class Biblio:
|
|
|
463
463
|
candidate.key = candidate_key_after
|
|
464
464
|
entries = []
|
|
465
465
|
for e in resolved:
|
|
466
|
-
|
|
466
|
+
# the existing entry keeps its key (and so does the single
|
|
467
|
+
# resolved entry that carries it, e.g. an overwrite with
|
|
468
|
+
# --update-key): only entries new to the library get a key
|
|
469
|
+
# regenerated from the template
|
|
470
|
+
keeps_key = e is candidate or (
|
|
471
|
+
len(resolved) == 1 and get_entry_val(e, 'ID', '') == candidate_key_before)
|
|
472
|
+
entries.extend( self.insert_entry(e, update_key and not keeps_key, rename=rename, copy=copy) )
|
|
467
473
|
return entries
|
|
468
474
|
|
|
469
475
|
|
|
@@ -480,13 +486,17 @@ class Biblio:
|
|
|
480
486
|
|
|
481
487
|
|
|
482
488
|
def set_files(self, entry, files, relative_to=None):
|
|
483
|
-
|
|
489
|
+
if relative_to is None:
|
|
490
|
+
relative_to = self.relative_to
|
|
491
|
+
entry['file'] = format_file(list(sorted(set(files), key=lambda f: files.index(f))), relative_to=relative_to)
|
|
484
492
|
# delete field if empty
|
|
485
493
|
if not entry['file'].strip():
|
|
486
494
|
del entry['file']
|
|
487
495
|
|
|
488
496
|
def get_files(self, entry, relative_to=None):
|
|
489
|
-
|
|
497
|
+
if relative_to is None:
|
|
498
|
+
relative_to = self.relative_to
|
|
499
|
+
return parse_file(get_entry_val(entry, 'file', ''), relative_to=relative_to)
|
|
490
500
|
|
|
491
501
|
def add_bibtex(self, bibtex, relative_to=None, attachments=None, convert_to_unicode=False, **kw):
|
|
492
502
|
bib = parse_string(bibtex)
|
|
@@ -522,7 +532,9 @@ class Biblio:
|
|
|
522
532
|
|
|
523
533
|
def add_bibtex_file(self, file, **kw):
|
|
524
534
|
bibtex = open(file).read()
|
|
525
|
-
|
|
535
|
+
# file links in the added bibtex are relative to its own directory
|
|
536
|
+
# (the absolute path matters: dirname('papers.bib') is '')
|
|
537
|
+
return self.add_bibtex(bibtex, relative_to=os.path.dirname(os.path.abspath(file)), **kw)
|
|
526
538
|
|
|
527
539
|
|
|
528
540
|
def fetch_doi(self, doi, **kw):
|