papers-cli 2.13__tar.gz → 2.14b0__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 (44) hide show
  1. {papers_cli-2.13 → papers_cli-2.14b0}/PKG-INFO +1 -1
  2. {papers_cli-2.13 → papers_cli-2.14b0}/papers/__main__.py +12 -3
  3. {papers_cli-2.13 → papers_cli-2.14b0}/papers/_version.py +2 -2
  4. {papers_cli-2.13 → papers_cli-2.14b0}/papers/bib.py +71 -8
  5. {papers_cli-2.13 → papers_cli-2.14b0}/papers/config.py +1 -1
  6. {papers_cli-2.13 → papers_cli-2.14b0}/papers/encoding.py +0 -1
  7. {papers_cli-2.13 → papers_cli-2.14b0}/papers_cli.egg-info/PKG-INFO +1 -1
  8. {papers_cli-2.13 → papers_cli-2.14b0}/.gitattributes +0 -0
  9. {papers_cli-2.13 → papers_cli-2.14b0}/.github/workflows/pypi.yml +0 -0
  10. {papers_cli-2.13 → papers_cli-2.14b0}/.github/workflows/tests.yml +0 -0
  11. {papers_cli-2.13 → papers_cli-2.14b0}/.gitignore +0 -0
  12. {papers_cli-2.13 → papers_cli-2.14b0}/LICENSE +0 -0
  13. {papers_cli-2.13 → papers_cli-2.14b0}/README.md +0 -0
  14. {papers_cli-2.13 → papers_cli-2.14b0}/papers/__init__.py +0 -0
  15. {papers_cli-2.13 → papers_cli-2.14b0}/papers/duplicate.py +0 -0
  16. {papers_cli-2.13 → papers_cli-2.14b0}/papers/extract.py +0 -0
  17. {papers_cli-2.13 → papers_cli-2.14b0}/papers/filename.py +0 -0
  18. {papers_cli-2.13 → papers_cli-2.14b0}/papers/latexenc.py +0 -0
  19. {papers_cli-2.13 → papers_cli-2.14b0}/papers/utils.py +0 -0
  20. {papers_cli-2.13 → papers_cli-2.14b0}/papers_cli.egg-info/SOURCES.txt +0 -0
  21. {papers_cli-2.13 → papers_cli-2.14b0}/papers_cli.egg-info/dependency_links.txt +0 -0
  22. {papers_cli-2.13 → papers_cli-2.14b0}/papers_cli.egg-info/entry_points.txt +0 -0
  23. {papers_cli-2.13 → papers_cli-2.14b0}/papers_cli.egg-info/requires.txt +0 -0
  24. {papers_cli-2.13 → papers_cli-2.14b0}/papers_cli.egg-info/top_level.txt +0 -0
  25. {papers_cli-2.13 → papers_cli-2.14b0}/pyproject.toml +0 -0
  26. {papers_cli-2.13 → papers_cli-2.14b0}/requirements.txt +0 -0
  27. {papers_cli-2.13 → papers_cli-2.14b0}/setup.cfg +0 -0
  28. {papers_cli-2.13 → papers_cli-2.14b0}/setup.py +0 -0
  29. {papers_cli-2.13 → papers_cli-2.14b0}/tests/__init__.py +0 -0
  30. {papers_cli-2.13 → papers_cli-2.14b0}/tests/common.py +0 -0
  31. {papers_cli-2.13 → papers_cli-2.14b0}/tests/config.py +0 -0
  32. {papers_cli-2.13 → papers_cli-2.14b0}/tests/download.py +0 -0
  33. {papers_cli-2.13 → papers_cli-2.14b0}/tests/downloadedpapers/.gitignore +0 -0
  34. {papers_cli-2.13 → papers_cli-2.14b0}/tests/downloadedpapers/bg-8-515-2011.txt +0 -0
  35. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_add.py +0 -0
  36. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_biblio.py +0 -0
  37. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_duplicates.py +0 -0
  38. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_encoding.py +0 -0
  39. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_extract.py +0 -0
  40. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_filecheck.py +0 -0
  41. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_install.py +0 -0
  42. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_list.py +0 -0
  43. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_misc.py +0 -0
  44. {papers_cli-2.13 → papers_cli-2.14b0}/tests/test_undo.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: papers-cli
3
- Version: 2.13
3
+ Version: 2.14b0
4
4
  Summary: utilities to keep your PDF library organized
5
5
  Author-email: Mahé Perrette <mahe.perrette@gmail.com>
6
6
  License: MIT
@@ -9,8 +9,6 @@ import subprocess as sp
9
9
  import shutil
10
10
  import itertools
11
11
  import fnmatch # unix-like match
12
- import hashlib
13
- import time
14
12
 
15
13
  import papers
16
14
  from papers import logger
@@ -19,7 +17,8 @@ from papers.extract import fetch_bibtex_by_doi, fetch_bibtex_by_fulltext_crossre
19
17
  from papers.encoding import parse_file, format_file, family_names, format_entries, standard_name, format_entry, parse_keywords, format_key
20
18
  from papers.config import bcolors, Config, search_config, CONFIG_FILE, CONFIG_FILE_LOCAL, DATA_DIR, CONFIG_FILE_LEGACY, BACKUP_DIR
21
19
  from papers.duplicate import list_duplicates, list_uniques, edit_entries
22
- from papers.bib import Biblio, FUZZY_RATIO, DEFAULT_SIMILARITY, entry_filecheck, backupfile as backupfile_func, isvalidkey, DuplicateKeyError
20
+ from papers.bib import (Biblio, FUZZY_RATIO, DEFAULT_SIMILARITY, entry_filecheck,
21
+ backupfile as backupfile_func, isvalidkey, DuplicateKeyError, clean_filesdir)
23
22
  from papers.utils import move, checksum, view_pdf, open_folder
24
23
  from papers import __version__
25
24
 
@@ -89,6 +88,9 @@ def _backup_bib(biblio, config, message=None):
89
88
  biblio.rename_entries_files(copy=True, relative_to=backupdir, hardlink=True)
90
89
  biblio.save(config.backupfile_clean)
91
90
  config.gitcmd(f"add {config.backupfile_clean.name}")
91
+
92
+ # Remove unlink files
93
+ clean_filesdir(biblio, interactive=False, ignore_files=[config.backupfile, config.backupfile_clean])
92
94
  config.gitcmd(f"add files")
93
95
 
94
96
  else:
@@ -673,6 +675,10 @@ def filecheckcmd(parser, o, config):
673
675
  if o.rename:
674
676
  biblio.rename_entries_files(o.copy)
675
677
 
678
+ if o.clean_filesdir:
679
+ print("Check files directory for unlinked files")
680
+ clean_filesdir(biblio, interactive=not o.force, ignore_files=[config.bibtex])
681
+
676
682
  savebib(biblio, config)
677
683
 
678
684
  def redocmd(parser, o, config):
@@ -1116,6 +1122,9 @@ def get_parser(config=None):
1116
1122
  filecheckp.add_argument('-d', '--delete-broken', action='store_true',
1117
1123
  help='remove file entry if the file link is broken')
1118
1124
 
1125
+ filecheckp.add_argument('--clean-filesdir', action='store_true',
1126
+ help='remove files in filesdir if not referred to in any entry')
1127
+
1119
1128
  filecheckp.add_argument('--fix-mendeley', action='store_true',
1120
1129
  help='fix a Mendeley bug where the leading "/" is omitted.')
1121
1130
 
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '2.13'
16
- __version_tuple__ = version_tuple = (2, 13)
15
+ __version__ = version = '2.14b0'
16
+ __version_tuple__ = version_tuple = (2, 14)
@@ -1,13 +1,8 @@
1
1
  import os
2
2
  from pathlib import Path
3
- import logging
4
- # logger.basicConfig(level=logger.INFO)
5
- import argparse
6
- import subprocess as sp
7
3
  import shutil
8
4
  import bisect
9
- import itertools
10
- import fnmatch # unix-like match
5
+ from unidecode import unidecode as unicode_to_ascii
11
6
  import bibtexparser
12
7
  from bibtexparser.customization import convert_to_unicode
13
8
 
@@ -18,8 +13,8 @@ from papers.extract import extract_pdf_doi, isvaliddoi, parse_doi
18
13
  from papers.extract import extract_pdf_metadata
19
14
  from papers.extract import fetch_bibtex_by_fulltext_crossref, fetch_bibtex_by_doi
20
15
 
21
- from papers.encoding import unicode_to_latex, unicode_to_ascii
22
16
  from papers.encoding import parse_file, format_file, standard_name, family_names, format_entries, update_file_path, format_entry
17
+ from papers.latexenc import unicode_to_latex, latex_to_unicode
23
18
 
24
19
  from papers.filename import NAMEFORMAT, KEYFORMAT
25
20
  from papers.utils import bcolors, checksum, move as _move
@@ -309,7 +304,7 @@ class Biblio:
309
304
  else:
310
305
  print(format_entry(self, entry, prefix="New entry"))
311
306
  print(format_entry(self, self.entries[i], prefix="Conflicts with"))
312
- raise DuplicateKeyError('Key conflict. Try update_key is True?')
307
+ raise DuplicateKeyError('Key conflict. Try update_key is True or specify --key KEY explicitly')
313
308
 
314
309
  else:
315
310
  logger.info('new entry: '+self.key(entry))
@@ -821,3 +816,71 @@ def entry_filecheck(e, delete_broken=False, fix_mendeley=False,
821
816
  newfiles.append(file)
822
817
 
823
818
  e['file'] = format_file(newfiles, relative_to=relative_to)
819
+
820
+
821
+ def clean_filesdir(biblio, interactive=True, ignore_files=None, ignore_folders=None):
822
+ if biblio.filesdir is None:
823
+ raise ValueError('filesdir is not defined, cannot clean')
824
+ removed_files = []
825
+
826
+ allfiles = set(os.path.abspath(file) for e in biblio.entries for file in biblio.get_files(e))
827
+ if ignore_files:
828
+ for f in ignore_files:
829
+ allfiles.add(os.path.abspath(f))
830
+ allfolders = set(os.path.abspath(folder) for e in biblio.entries for folder in {os.path.dirname(file) for file in biblio.get_files(e)})
831
+
832
+ if ignore_folders is None:
833
+ ignore_folders = []
834
+
835
+ for root, direcs, files in os.walk(biblio.filesdir):
836
+
837
+ ANS = None # Y(es) or N(o) for all files in this folder (reset at each pass)
838
+ if root in ignore_folders:
839
+ continue
840
+ if '.git' in root.split(os.path.sep):
841
+ continue
842
+ for file in files:
843
+ path = os.path.abspath(os.path.join(root, file))
844
+ if file.startswith('.') or file.endswith('.bib'):
845
+ continue
846
+ if path not in allfiles:
847
+ if interactive:
848
+ if ANS is None:
849
+ ans = input(f"File: {os.path.relpath(path, biblio.filesdir)} not in library. Remove ? [Y/n/Y/N] ")
850
+ else:
851
+ ans = ANS
852
+ if ans in ['Y', 'N']:
853
+ ans = ANS = ans.lower() # same reply for all files in this folder
854
+ if ans.lower() == 'y':
855
+ os.remove(path)
856
+ removed_files.append(path)
857
+ else:
858
+ logger.info(f"Remove unlinked file {os.path.relpath(path, biblio.filesdir)}.")
859
+ os.remove(path)
860
+ removed_files.append(path)
861
+
862
+ for direc in direcs:
863
+ if direc.startswith('.'):
864
+ continue
865
+ if direc in ignore_folders:
866
+ continue
867
+
868
+ # Check multifile entries
869
+ bibtex = os.path.join(root, direc, '.'+direc+'.bib')
870
+ if not os.path.exists(bibtex):
871
+ continue
872
+
873
+ direcpath = os.path.abspath(os.path.join(root, direc))
874
+
875
+ if direcpath not in allfolders:
876
+ if interactive:
877
+ ans = input(f"Folder: {os.path.relpath(direcpath, root)} not in library. Remove ? [Y/n] ")
878
+ if ans.lower() == 'y':
879
+ shutil.rmtree(os.path.join(root, direcpath))
880
+ else:
881
+ logger.info(f"Remove folder {direc}.")
882
+ shutil.rmtree(os.path.join(root, direcpath))
883
+
884
+ break
885
+
886
+ return removed_files
@@ -85,7 +85,7 @@ class Config:
85
85
  return Path(os.path.sep)
86
86
 
87
87
  def gitcmd(self, cmd, check=True, **kw):
88
- logger.debug(f"git add {self.backupfile.name}")
88
+ logger.debug(f"git {cmd} -C {self.gitdir}")
89
89
  try:
90
90
  sp.run(
91
91
  f"git {cmd}",
@@ -2,7 +2,6 @@ import os
2
2
  import bibtexparser
3
3
  from pathlib import Path
4
4
  from unidecode import unidecode as unicode_to_ascii
5
- from papers.latexenc import unicode_to_latex
6
5
  from papers.utils import ansi_link as link, bcolors
7
6
  from papers import logger
8
7
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: papers-cli
3
- Version: 2.13
3
+ Version: 2.14b0
4
4
  Summary: utilities to keep your PDF library organized
5
5
  Author-email: Mahé Perrette <mahe.perrette@gmail.com>
6
6
  License: MIT
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