Created
August 10, 2020 23:06
-
-
Save sosi-deadeye/ea9d82467f2b4c65c79bc5cbb75c343c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
This program find files by following pattern: | |
> dog000001.txt | |
> cat000054.txt | |
> lion010101.txt | |
> mouse123456.txt | |
Visit for more info: https://python-forum.io/Thread-Listing-files-with-glob | |
The files are returned in sorted order by name and then by integer. | |
By the way, it's totally over engineered and you should not use this. | |
""" | |
import re | |
import sys | |
import json | |
from argparse import ArgumentParser, Namespace | |
from pathlib import Path | |
from typing import Union, Optional, Generator, Callable, List, Tuple, Any | |
PATH = Union[str, Path] | |
PATH_GLOB = Generator[Path, None, None] | |
FIND_RESULT = Tuple[str, int, Path] | |
FIND_RESULTS = List[FIND_RESULT] | |
SORT_FUNC = Optional[Callable[[FIND_RESULT], Tuple[Any]]] | |
REGEX = re.compile(r"^([a-zA-Z])+(\d{6})$") | |
def get_txt(root: PATH) -> PATH_GLOB: | |
""" | |
:param root: Path where to find the txt files | |
:return: A generator which yields Path objects | |
""" | |
yield from Path(root).glob("*.txt") | |
def find(root: PATH, sort_func: SORT_FUNC = None) -> FIND_RESULTS: | |
""" | |
:param root: Path where to find the txt files | |
:param sort_func: Sort Function which takes a FIND_RESULT | |
:return: A generator which yields FIND_RESULT | |
""" | |
regex = REGEX | |
files: FIND_RESULTS = [] | |
for file in get_txt(root): | |
if match := regex.search(file.stem): | |
name = match.group(1) | |
number = int(match.group(2)) | |
files.append((name, number, file)) | |
files.sort(key=sort_func) | |
return files | |
def by_number(result: FIND_RESULT) -> Tuple[int, str]: | |
""" | |
Key function to sort results by number and then by name | |
:param result: | |
:return: | |
""" | |
return result[1], result[0] | |
def print_results(results: FIND_RESULTS, count: bool = False) -> None: | |
""" | |
Print results to stdout | |
:param results: The results from find | |
:param count: Print the count of matches at the end | |
:return: | |
""" | |
for *_, file in results: | |
print(file) | |
if count: | |
print(f"{len(results)} matching files found.") | |
# def print_json_stream(results: FIND_RESULTS) -> None: | |
# """ | |
# DoNotUseThisCode | |
# otherwise implement escaping | |
# """ | |
# count = len(results) | |
# header = f'{{"count":{count},"results":[' | |
# print(header, end="", flush=True) | |
# for index, (*_, file) in enumerate(results, 1): | |
# time.sleep(2) | |
# print(f'"{file}"', flush=True, end="") | |
# if index < count: | |
# print(",", flush=True, end="") | |
# print("]}") | |
def print_json(results: FIND_RESULTS) -> None: | |
""" | |
Print the results as json to stdout | |
:param results: | |
:return: | |
""" | |
files = [str(file) for *_, file in results] | |
result = { | |
"count": len(files), | |
"results": files, | |
} | |
print(json.dumps(result)) | |
def get_args() -> Namespace: | |
""" | |
Get arguments | |
:return: parsed arguments | |
""" | |
desc = f""" | |
This example program finds txt files | |
and uses the internal specified regex to match | |
them. | |
The following regex is used: {REGEX.pattern} | |
""" | |
parser = ArgumentParser(description=desc) | |
# noinspection PyTypeChecker | |
parser.add_argument("root", type=Path, help="Root path where to search the files.") | |
parser.add_argument( | |
"-n", | |
action="store_const", | |
const=by_number, | |
default=None, | |
help="Sort first by numeric value and then by name.", | |
) | |
parser.add_argument( | |
"-c", action="store_true", help="Show at the end the file count." | |
) | |
parser.add_argument("-j", action="store_true", help="Json stream output") | |
arguments = parser.parse_args() | |
if not arguments.root.exists(): | |
raise FileNotFoundError("Path does not exist.") | |
if not arguments.root.is_dir(): | |
raise FileNotFoundError("Path is not a directory.") | |
return arguments | |
if __name__ == "__main__": | |
try: | |
args = get_args() | |
except FileNotFoundError as e: | |
print(e, file=sys.stderr) | |
sys.exit(1) | |
if args.j: | |
print_json(find(args.root, args.n)) | |
else: | |
print_results(results=find(args.root, args.n), count=args.c) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment