skilleter-thingy 0.1.18__py3-none-any.whl → 0.1.21__py3-none-any.whl

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.

Potentially problematic release.


This version of skilleter-thingy might be problematic. Click here for more details.

Files changed (33) hide show
  1. skilleter_thingy/ffind.py +2 -2
  2. skilleter_thingy/ggit.py +1 -1
  3. skilleter_thingy/ggrep.py +2 -1
  4. skilleter_thingy/git_br.py +3 -3
  5. skilleter_thingy/git_common.py +2 -2
  6. skilleter_thingy/git_hold.py +6 -6
  7. skilleter_thingy/git_parent.py +4 -3
  8. skilleter_thingy/git_review.py +16 -12
  9. skilleter_thingy/git_update.py +2 -2
  10. skilleter_thingy/git_wt.py +5 -5
  11. skilleter_thingy/gitcmp_helper.py +6 -1
  12. skilleter_thingy/gphotosync.py +12 -8
  13. skilleter_thingy/localphotosync.py +77 -358
  14. skilleter_thingy/multigit.py +30 -34
  15. skilleter_thingy/photodupe.py +10 -10
  16. skilleter_thingy/py_audit.py +4 -2
  17. skilleter_thingy/readable.py +13 -11
  18. skilleter_thingy/sysmon.py +2 -2
  19. skilleter_thingy/thingy/colour.py +6 -2
  20. skilleter_thingy/thingy/dircolors.py +20 -18
  21. skilleter_thingy/thingy/git2.py +0 -1
  22. skilleter_thingy/thingy/popup.py +1 -1
  23. skilleter_thingy/thingy/tfm_pane.py +3 -3
  24. skilleter_thingy/thingy/tidy.py +14 -13
  25. skilleter_thingy/trimpath.py +5 -4
  26. skilleter_thingy/venv_create.py +1 -1
  27. {skilleter_thingy-0.1.18.dist-info → skilleter_thingy-0.1.21.dist-info}/METADATA +1 -1
  28. skilleter_thingy-0.1.21.dist-info/PKG-INFO 2 +193 -0
  29. {skilleter_thingy-0.1.18.dist-info → skilleter_thingy-0.1.21.dist-info}/RECORD +33 -32
  30. {skilleter_thingy-0.1.18.dist-info → skilleter_thingy-0.1.21.dist-info}/WHEEL +0 -0
  31. {skilleter_thingy-0.1.18.dist-info → skilleter_thingy-0.1.21.dist-info}/entry_points.txt +0 -0
  32. {skilleter_thingy-0.1.18.dist-info → skilleter_thingy-0.1.21.dist-info}/licenses/LICENSE +0 -0
  33. {skilleter_thingy-0.1.18.dist-info → skilleter_thingy-0.1.21.dist-info}/top_level.txt +0 -0
skilleter_thingy/ffind.py CHANGED
@@ -380,10 +380,10 @@ def validate_arguments(args):
380
380
 
381
381
  if args.git:
382
382
  if git.working_tree() is None:
383
- colour.error('[RED:ERROR]: The current directory is not inside a git working tree')
383
+ colour.error('The current directory is not inside a git working tree', prefix=True)
384
384
 
385
385
  if args.dir:
386
- colour.error('[RED:ERROR]: Git does not track directories, so you cannot search for them in a git working tree')
386
+ colour.error('Git does not track directories, so you cannot search for them in a git working tree', prefix=True)
387
387
 
388
388
  if args.verbose:
389
389
  print(f'Searching directory "{args.path}" for matches with "{args.patterns}"')
skilleter_thingy/ggit.py CHANGED
@@ -55,7 +55,7 @@ def main():
55
55
  try:
56
56
  os.chdir(args.path)
57
57
  except FileNotFoundError:
58
- colour.error(f'[RED:ERROR]: Invalid path [BLUE:{args.path}]')
58
+ colour.error(f'Invalid path [BLUE:{args.path}]', prefix=True)
59
59
 
60
60
  # If the current directory is in a working tree and below the top-level
61
61
  # directory then we run the git command here as well as in subdirectories
skilleter_thingy/ggrep.py CHANGED
@@ -39,7 +39,8 @@ def parse_command_line():
39
39
  parser.add_argument('--files-with-matches', '-l', action='store_true', help='Show only the names of files that contain matches')
40
40
  parser.add_argument('--files-without-matches', '-L', action='store_true', help='Show only the names of files that do NOT contain matches')
41
41
  parser.add_argument('--wildcard', '-W', action='append', help='Only search files matching the wildcard(s)')
42
- parser.add_argument('--only-matching', '-o', action='store_true', help='Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.')
42
+ parser.add_argument('--only-matching', '-o', action='store_true',
43
+ help='Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.')
43
44
  parser.add_argument('--no-color', action='store_true', help='Turn off match highlighting')
44
45
  parser.add_argument('pattern', action='store', help='Regular expression to search for')
45
46
  parser.add_argument('paths', nargs='*', help='Optional list of one or more paths to search')
@@ -39,7 +39,7 @@ def parse_command_line():
39
39
  args = parser.parse_args()
40
40
 
41
41
  if args.delete and not args.branches:
42
- colour.error('[RED:ERROR]: You must specify the branches to delete')
42
+ colour.error('You must specify the branches to delete', prefix=True)
43
43
 
44
44
  return args
45
45
 
@@ -105,7 +105,7 @@ def list_branches(branches):
105
105
  output = []
106
106
 
107
107
  for i, field in enumerate(branch):
108
- if i==1:
108
+ if i == 1:
109
109
  field = parse(field)
110
110
  time_str = field.strftime('%H:%M:%S')
111
111
 
@@ -172,7 +172,7 @@ def git_br():
172
172
  except BrokenPipeError:
173
173
  sys.exit(2)
174
174
  except git.GitError as exc:
175
- colour.error(f'[RED:ERROR]: {exc.msg}', status=exc.status)
175
+ colour.error(exc.msg, status=exc.status, prefix=True)
176
176
 
177
177
  ################################################################################
178
178
 
@@ -27,12 +27,12 @@ def main():
27
27
  args = parser.parse_args()
28
28
 
29
29
  if args.long and args.short:
30
- colour.error('[RED:ERROR]: The [BLUE:--long] and [BLUE:--short] options cannot be used together')
30
+ colour.error('The [BLUE:--long] and [BLUE:--short] options cannot be used together', prefix=True)
31
31
 
32
32
  try:
33
33
  ancestor = git.find_common_ancestor(args.commit1, args.commit2)
34
34
  except git.GitError as exc:
35
- colour.error(f'[RED:ERROR]: {exc}', status=exc.status)
35
+ colour.error(exc, status=exc.status, prefix=True)
36
36
 
37
37
  if args.short:
38
38
  print(ancestor)
@@ -48,13 +48,13 @@ def archive_branches(branches):
48
48
 
49
49
  for branch in branches:
50
50
  if not git.isbranch(branch):
51
- colour.error(f'[RED:ERROR:] Branch {branch} does not exist')
51
+ colour.error(f'Branch {branch} does not exist', prefix=True)
52
52
 
53
53
  if archive_tag_name(branch) in tags:
54
- colour.error(f'[RED:ERROR:] An archive tag already exists for branch {branch}')
54
+ colour.error(f'An archive tag already exists for branch {branch}', prefix=True)
55
55
 
56
56
  if branch == current_branch:
57
- colour.error('[RED:ERROR:] Cannot archive the current branch')
57
+ colour.error('Cannot archive the current branch', prefix=True)
58
58
 
59
59
  for branch in branches:
60
60
  tag_name = archive_tag_name(branch)
@@ -96,7 +96,7 @@ def restore_archive_branches(branches):
96
96
 
97
97
  for branch in branches:
98
98
  if archive_tag_name(branch) not in tags:
99
- colour.error(f'[RED:ERROR:] Archive branch {branch} does not exist')
99
+ colour.error(f'Archive branch {branch} does not exist', prefix=True)
100
100
 
101
101
  archive_tag_names = []
102
102
 
@@ -123,10 +123,10 @@ def main():
123
123
  args = parser.parse_args()
124
124
 
125
125
  if args.list and args.restore:
126
- colour.error('[RED:ERROR:] The list and restore options cannot be specified together')
126
+ colour.error('The list and restore options cannot be specified together', prefix=True)
127
127
 
128
128
  if not args.branches and not args.list:
129
- colour.error('[RED:ERROR:] No branches specified')
129
+ colour.error('No branches specified', prefix=True)
130
130
 
131
131
  if args.list:
132
132
  list_archive_branches(args.branches)
@@ -23,7 +23,8 @@ def main():
23
23
  parser = argparse.ArgumentParser(description='Attempt to determine the parent branch for the specified branch (defaulting to the current one)')
24
24
  parser.add_argument('--all', '-a', action='store_true', help='Include feature branches as possible parents')
25
25
  parser.add_argument('--verbose', '-v', action='store_true', help='Report verbose results (includes number of commits between branch and parent)')
26
- parser.add_argument('branch', action='store', nargs='?', type=str, default=current_branch, help=f'Branch, commit or commit (defaults to current branch; {current_branch})')
26
+ parser.add_argument('branch', action='store', nargs='?', type=str, default=current_branch,
27
+ help=f'Branch, commit or commit (defaults to current branch; {current_branch})')
27
28
 
28
29
  args = parser.parse_args()
29
30
 
@@ -48,7 +49,7 @@ def main():
48
49
  parents.append(more)
49
50
 
50
51
  except git.GitError as exc:
51
- colour.error(f'[RED:ERROR:] {exc.msg}', status=exc.status)
52
+ colour.error(exc.msg, status=exc.status, prefix=True)
52
53
 
53
54
  if parents:
54
55
  if args.verbose:
@@ -59,7 +60,7 @@ def main():
59
60
  else:
60
61
  print(', '.join(parents))
61
62
  else:
62
- colour.error('[RED:Could not determine parent branch]\n')
63
+ colour.error('Could not determine parent branch\n', prefix=True)
63
64
 
64
65
  ################################################################################
65
66
 
@@ -228,7 +228,11 @@ class GitReview():
228
228
 
229
229
  # Move to the top-level directory in the working tree
230
230
 
231
- self.current_dir = os.getcwd()
231
+ try:
232
+ self.current_dir = os.getcwd()
233
+ except FileNotFoundError:
234
+ raise GitReviewError('Unable to locate current directory')
235
+
232
236
  self.working_tree_dir = git.working_tree()
233
237
 
234
238
  if not self.working_tree_dir:
@@ -444,7 +448,7 @@ class GitReview():
444
448
  self.filter_modified = pickle_data.get('filter_modified', self.filter_modified)
445
449
  self.sort_order = pickle_data.get('sort_order', self.sort_order)
446
450
  self.reverse_sort = pickle_data.get('reverse_sort', self.reverse_sort)
447
- self.filter_none_whitespace_only= pickle_data.get('filter_none_whitespace_only', self.filter_none_whitespace_only)
451
+ self.filter_none_whitespace_only = pickle_data.get('filter_none_whitespace_only', self.filter_none_whitespace_only)
448
452
  self.show_none_whitespace_stats = pickle_data.get('show_none_whitespace_stats', self.show_none_whitespace_stats)
449
453
 
450
454
  # Transfer the reviewed flag for each file in the pickle
@@ -456,7 +460,7 @@ class GitReview():
456
460
  newfile['reviewed'] = oldfile['reviewed']
457
461
  break
458
462
 
459
- except (EOFError, pickle.UnpicklingError, ModuleNotFoundError, AttributeError): # TODO: Why did I get ModuleNotFoundError or AttributeError????
463
+ except (EOFError, pickle.UnpicklingError, ModuleNotFoundError, AttributeError): # TODO: Why did I get ModuleNotFoundError or AttributeError????
460
464
  pass
461
465
 
462
466
  self.__constrain_display_parameters()
@@ -1309,13 +1313,13 @@ def parse_command_line():
1309
1313
  # Make sure that we're actually in a git working tree
1310
1314
 
1311
1315
  if not git.working_tree():
1312
- colour.error('[RED:ERROR] Not a git repository')
1316
+ colour.error('Not a git repository', prefix=True)
1313
1317
 
1314
1318
  # -C/--change is shorthand for '--commit HEAD^'
1315
1319
 
1316
1320
  if args.change:
1317
1321
  if args.commits:
1318
- colour.error('[RED:ERROR] The -C/--change option does not take parameters')
1322
+ colour.error('The -C/--change option does not take parameters', prefix=True)
1319
1323
 
1320
1324
  args.commits = ['HEAD^']
1321
1325
 
@@ -1345,7 +1349,7 @@ def parse_command_line():
1345
1349
  paths.append(entry)
1346
1350
  parsing_commits = False
1347
1351
  else:
1348
- colour.error(f'[RED:ERROR] Invalid path/commit: {entry}')
1352
+ colour.error(f'Invalid path/commit: {entry}', prefix=True)
1349
1353
 
1350
1354
  args.commits = commits
1351
1355
  args.paths = paths
@@ -1353,13 +1357,13 @@ def parse_command_line():
1353
1357
  # Validate the commits & paths
1354
1358
 
1355
1359
  if len(args.commits) > 2:
1356
- colour.error('[RED:ERROR]: No more than 2 commits can be specified')
1360
+ colour.error('No more than 2 commits can be specified', prefix=True)
1357
1361
 
1358
1362
  if (args.branch or args.commit) and args.commits:
1359
- colour.error('[RED:ERROR]: Additional commits should not be specified in conjunction with the -b/--branch option')
1363
+ colour.error('Additional commits should not be specified in conjunction with the -b/--branch option', prefix=True)
1360
1364
 
1361
1365
  if args.commit and args.branch:
1362
- colour.error('[RED:ERROR]: The -c/--commit and -b/--branch options are mutually exclusive')
1366
+ colour.error('The -c/--commit and -b/--branch options are mutually exclusive', prefix=True)
1363
1367
 
1364
1368
  # If the -c/--commit option is used, then review against its parent
1365
1369
  # If the -b/--branch option is used, then review against the oldest common ancestor
@@ -1369,7 +1373,7 @@ def parse_command_line():
1369
1373
  try:
1370
1374
  args.commits = [git.find_common_ancestor('HEAD', args.branch)]
1371
1375
  except git.GitError as exc:
1372
- colour.error(f'[ERROR]: {exc}', status=exc.status)
1376
+ colour.error(exc, status=exc.status, prefix=True)
1373
1377
 
1374
1378
  elif args.commit:
1375
1379
  args.commits = ['%s^' % args.commit, args.commit]
@@ -1387,9 +1391,9 @@ def parse_command_line():
1387
1391
  if len(matches) == 1:
1388
1392
  args.commits[i] = matches[0]
1389
1393
  else:
1390
- colour.error(f'[RED:ERROR]: Multiple commits match {entry}')
1394
+ colour.error(f'Multiple commits match {entry}', prefix=True)
1391
1395
  else:
1392
- colour.error(f'[RED:ERROR] {entry} is not a valid commit ID')
1396
+ colour.error(f'{entry} is not a valid commit ID', prefix=True)
1393
1397
 
1394
1398
  # Things work easier if we always have two commits to compare
1395
1399
 
@@ -85,7 +85,7 @@ def branch_rebase(args, results, branch):
85
85
  if args.all_parents:
86
86
  parents, _ = git.parents()
87
87
  else:
88
- parents, _ = git.parents(ignore='feature/*' )
88
+ parents, _ = git.parents(ignore='feature/*')
89
89
 
90
90
  logging.debug('Probable parents of %s: %s', branch, parents)
91
91
 
@@ -314,7 +314,7 @@ def main():
314
314
 
315
315
  # List of stuff that's been done, to report in the summary
316
316
 
317
- results = {'deleted': set(), 'pulled': set(), 'failed': set(), 'rebased': set(), 'unchanged': set(), 'no-tracking': set() }
317
+ results = {'deleted': set(), 'pulled': set(), 'failed': set(), 'rebased': set(), 'unchanged': set(), 'no-tracking': set()}
318
318
 
319
319
  to_rebase = set()
320
320
 
@@ -26,15 +26,15 @@ def main():
26
26
  parser = argparse.ArgumentParser(description='Report top-level directory of the current git working tree.')
27
27
  parser.add_argument('--parent', '-p', action='store_true',
28
28
  help='If we are already at the top of the working tree, check if the parent directory is in a working tree and output the top-level directory of that tree.')
29
- parser.add_argument('--dir', '-d', action='store', default=os.getcwd(),
29
+ parser.add_argument('--dir', '-d', action='store', default=None,
30
30
  help='Find the location of the top-level directory in the working tree starting at the specified directory')
31
31
 
32
32
  args = parser.parse_args()
33
33
 
34
- start_dir = os.path.abspath(args.dir)
35
-
36
- if not os.path.isdir(start_dir):
37
- sys.stderr.write(f'Unable to locate directory {args.dir}\n')
34
+ try:
35
+ start_dir = os.path.abspath(args.dir or os.getcwd())
36
+ except FileNotFoundError:
37
+ sys.stderr.write('Unable to determine initial directory\n')
38
38
  sys.exit(1)
39
39
 
40
40
  # Search for a .git directory in the current or parent directories
@@ -169,7 +169,12 @@ def main():
169
169
 
170
170
  # Determine the best way of reporting the path to the file
171
171
 
172
- working_tree_path = os.getcwd()
172
+ try:
173
+ working_tree_path = os.getcwd()
174
+ except FileNotFoundError:
175
+ sys.stderr.write('Unable to get current working directory')
176
+ sys.exit(2)
177
+
173
178
  current_path = os.path.join(working_tree_path, os.getenv('GIT_SUBDIR', ''))
174
179
 
175
180
  current_file_path = os.path.relpath(args.file_path if args.new_name is None else args.new_name, current_path)
@@ -94,7 +94,7 @@ def parse_yyyymm(datestr):
94
94
  date_match = YYYY_MM_re.fullmatch(datestr)
95
95
 
96
96
  if not date_match:
97
- colour.error(f'ERROR: Invalid date: {datestr}')
97
+ colour.error(f'Invalid date: {datestr}', prefix=True)
98
98
 
99
99
  return datetime.date(int(date_match.group(1)), int(date_match.group(2)), day=1)
100
100
 
@@ -111,15 +111,19 @@ def parse_command_line():
111
111
 
112
112
  parser.add_argument('--verbose', '-v', action='store_true', help='Output verbose status information')
113
113
  parser.add_argument('--dryrun', '-D', action='store_true', help='Just list files to be copied, without actually copying them')
114
- parser.add_argument('--picturedir', '-P', action='store', default=DEFAULT_PHOTO_DIR, help=f'Location of local picture storage directory (defaults to {DEFAULT_PHOTO_DIR})')
115
- parser.add_argument('--videodir', '-V', action='store', default=DEFAULT_VIDEO_DIR, help=f'Location of local video storage directory (defaults to {DEFAULT_VIDEO_DIR})')
114
+ parser.add_argument('--picturedir', '-P', action='store', default=DEFAULT_PHOTO_DIR,
115
+ help=f'Location of local picture storage directory (defaults to {DEFAULT_PHOTO_DIR})')
116
+ parser.add_argument('--videodir', '-V', action='store', default=DEFAULT_VIDEO_DIR,
117
+ help=f'Location of local video storage directory (defaults to {DEFAULT_VIDEO_DIR})')
116
118
  parser.add_argument('--start', '-s', action='store', default=None, help='Start date (in the form YYYY-MM, defaults to current month)')
117
119
  parser.add_argument('--end', '-e', action='store', default=None, help=f'End date (in the form YYYY-MM, defaults to {DEFAULT_MONTHS} before the start date)')
118
120
  parser.add_argument('--months', '-m', action='store', type=int, default=None, help='Synchronise this number of months of data (current month included)')
119
121
  parser.add_argument('--cache', '-c', action='store', default=DEFAULT_CACHE_DIR, help=f'Cache directory for Google photos (defaults to {DEFAULT_CACHE_DIR})')
120
- parser.add_argument('--rclone', '-r', action='store', default=DEFAULT_RCLONE_REMOTE, help=f'rclone remote name for Google photos (defaults to {DEFAULT_RCLONE_REMOTE})')
122
+ parser.add_argument('--rclone', '-r', action='store', default=DEFAULT_RCLONE_REMOTE,
123
+ help=f'rclone remote name for Google photos (defaults to {DEFAULT_RCLONE_REMOTE})')
121
124
  parser.add_argument('--no-update', '-N', action='store_true', help='Do not update local cache')
122
- parser.add_argument('--keep', '-k', action='store', type=int, default=DEFAULT_KEEP, help=f'Keep this number of months before the start date in the cache (defaults to {DEFAULT_KEEP})')
125
+ parser.add_argument('--keep', '-k', action='store', type=int, default=DEFAULT_KEEP,
126
+ help=f'Keep this number of months before the start date in the cache (defaults to {DEFAULT_KEEP})')
123
127
  parser.add_argument('--skip-no-day', '-z', action='store_true', help='Don\'t sync files where the day of the month could not be determined')
124
128
  parser.add_argument('action', nargs='*', help='Actions to perform (report or sync)')
125
129
 
@@ -387,9 +391,9 @@ def update_cache(args, year, month):
387
391
 
388
392
  subprocess.run(cmd, check=True)
389
393
  except subprocess.CalledProcessError:
390
- colour.error(f'[RED:ERROR]: Failed to sync Google photos for month [BLUE:{month}] of year [BLUE:{year}]')
394
+ colour.error(f'Failed to sync Google photos for month [BLUE:{month}] of year [BLUE:{year}]', prefix=True)
391
395
  except FileNotFoundError as exc:
392
- colour.error('f[RED:ERROR]: {exc}')
396
+ colour.error(exc, prefix=True)
393
397
 
394
398
  ################################################################################
395
399
 
@@ -450,7 +454,7 @@ def remove_duplicates(media_files):
450
454
  # Originals can have upper or lower case extensions, copies only tend to have lower
451
455
  # case, so build a lower case to original lookup table
452
456
 
453
- names = {name.lower():name for name in media_files}
457
+ names = {name.lower(): name for name in media_files}
454
458
 
455
459
  duplicates = defaultdict(list)
456
460