Browse Source

Initial commit

master
IamTheFij 12 months ago
parent
commit
0ed1b94969
  1. 1
      .gitignore
  2. 27
      .pre-commit-config.yaml
  3. 2
      README.md
  4. 128
      paddy

1
.gitignore

@ -137,4 +137,3 @@ dmypy.json
# Cython debug symbols
cython_debug/

27
.pre-commit-config.yaml

@ -0,0 +1,27 @@
---
default_language_version:
python: python3.8
repos:
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:
- id: black
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
hooks:
- id: check-added-large-files
- id: check-merge-conflict
- id: debug-statements
- id: end-of-file-fixer
- id: fix-encoding-pragma
- id: trailing-whitespace
- id: name-tests-test
exclude: tests/(common.py|util.py|(helpers|integration/factories)/(.+).py)
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.4.0
hooks:
- id: reorder-python-imports
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.800
hooks:
- id: mypy

2
README.md

@ -1,3 +1,3 @@
# paddy-files
Zero-padding numeric filenames
Zero-padding numeric filenames

128
paddy

@ -0,0 +1,128 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import re
from pathlib import Path
from typing import List
from typing import Optional
num_matcher = re.compile(r"([0-9]+)")
def extract_numbers(s: str) -> str:
number_match = num_matcher.search(s)
if number_match:
return number_match.group(1)
return ""
def calc_pad_length(files: List[Path]) -> int:
max_len = 0
for f in files:
numbers = extract_numbers(f.name)
max_len = max(len(numbers), max_len)
return max_len
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Pads numbers in file names so they consistently align and sort"
)
parser.add_argument("files", nargs="+", metavar="file", help="Files to be renamed")
parser.add_argument(
"-l",
"--length",
type=int,
help="Length of numbers after padding (default: auto)",
)
parser.add_argument(
"-f",
"--force",
action="store_true",
help="Force rename, even if file at destination exists",
)
parser.add_argument(
"-v", "--verbose", action="store_true", help="Print all actions"
)
parser.add_argument(
"-d",
"--dry-run",
action="store_true",
help="Print actions only without modifying any file. Implies --verbose",
)
parser.add_argument(
"-i",
"--ignore",
metavar="REGEX",
help="Regular expression used to ignore files matching the name",
)
parser.add_argument(
"--ignore-files",
nargs="+",
metavar="IGNOREFILE",
help="Files to ignore for renaming. Must add -- before positional arguments",
)
args = parser.parse_args()
# Dry run implies verbose
if args.dry_run:
args.verbose = True
return args
def main() -> int:
args = parse_args()
# Compile ignore pattern, if provided
ignore_matcher: Optional[re.Pattern] = None
if args.ignore:
ignore_matcher = re.compile(args.ignore)
# Build list of files to act on
p = Path(".")
files = []
for f in args.files:
if args.ignore_files and f in args.ignore_files:
continue
if ignore_matcher and ignore_matcher.match(f):
continue
files.append(p / f)
pad_len = args.length
if pad_len is None:
pad_len = calc_pad_length(files)
if args.verbose:
print(f"Padding to {pad_len}")
status = 0
for f in files:
numbers = extract_numbers(f.name)
if len(numbers) == pad_len:
if args.verbose:
print(f"{f.name} is already padded.")
continue
# Pad number and get destination path
new_numbers = numbers.zfill(pad_len)
new_name = num_matcher.sub(new_numbers, f.name, count=1)
new_file = f.parent / new_name
# Possibly rename unless exists or forced
if not new_file.exists() or args.force:
if args.verbose:
print(f"Rename {f.name} to {new_file.name}")
f.rename(new_file)
else:
print(
f"Could not ename {f.name} to {new_file.name}. Destination file exists."
)
status = 1
return status
if __name__ == "__main__":
exit(main())
Loading…
Cancel
Save