diff --git a/tests/test_cli.py b/tests/test_cli.py index c2334ba..e6b7659 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -32,7 +32,7 @@ # load local module rather than system installed version import sys -project_root = Path(__file__).resolve().parent.parent +project_root = str(Path(__file__).resolve().parent.parent) sys.path.insert(0, project_root) # module to test diff --git a/tests/test_toc.py b/tests/test_toc.py index f4f4d06..3009961 100644 --- a/tests/test_toc.py +++ b/tests/test_toc.py @@ -29,7 +29,7 @@ # load local module rather than system installed version import sys -project_root = Path(__file__).resolve().parent.parent +project_root = str(Path(__file__).resolve().parent.parent) sys.path.insert(0, project_root) # module to test @@ -46,7 +46,7 @@ def test_set_extension(self): ("file.c", "c"), ("file.ini", "ini"), (".", ""), - ("./../", "/"), + ("./../", ""), ("file.unknown", "unknown"), ("file.", ""), ] @@ -54,7 +54,7 @@ def test_set_extension(self): with self.subTest( input_file=input_file, expected_extension=expected_extension ): - t = Toc(input_file) + t = Toc(Path(input_file)) actual_extension = t.extension self.assertEqual( actual_extension, @@ -76,7 +76,7 @@ def test_set_character(self): with self.subTest( input_file=input_file, expected_character=expected_character ): - t = Toc(input_file) + t = Toc(Path(input_file)) actual_character = t.set_character() self.assertEqual( actual_character, @@ -92,7 +92,8 @@ def test_toc_prefix_suffix(self): "": ([], []), } for extension, (expected_prefix, expected_suffix) in test_cases.items(): - t = Toc("mock.txt") + input_file = Path("mock.txt") + t = Toc(input_file) t.extension = extension actual_prefix, actual_suffix = t._toc_prefix_suffix() comparison = ( @@ -107,7 +108,8 @@ def test_toc_prefix_suffix(self): ) def test_process_generic_1(self): - t = Toc("mock.txt") + input_file = Path("mock.txt") + t = Toc(input_file) lines = [ "# ################################################################ Heading 1" ] @@ -116,7 +118,8 @@ def test_process_generic_1(self): self.assertEqual(result, expected) def test_process_generic_2n(self): - t = Toc("mock.beancount") + input_file = Path("mock.beancount") + t = Toc(input_file) t.set_character() lines = ["*** Transactions"] expected = ["; │ └── Transactions"] @@ -124,7 +127,8 @@ def test_process_generic_2n(self): self.assertEqual(result, expected) def test_prettify_connectors(self): - t = Toc("mock.txt") + input_file = Path("mock.txt") + t = Toc(input_file) input_list = [ "# ├── MODULES", "# ├── CLASS", @@ -179,7 +183,8 @@ def test_read_file(self): "builtins.open", side_effect=UnicodeDecodeError("utf-8", b"", 1, 2, "mock reason"), ): - t = Toc("mock.txt") + input_file = Path("mock.txt") + t = Toc(input_file) data = t._read_file() self.assertEqual(data, "") self.assertEqual(t.err, "binary") diff --git a/toc/cli.py b/toc/cli.py index 508fcbd..89e1c5d 100755 --- a/toc/cli.py +++ b/toc/cli.py @@ -27,11 +27,14 @@ import sys # glob expansion -import glob +# import glob # version from importlib_metadata import version +# robust file handling +from pathlib import Path + # toc library from toc.toc import Toc @@ -65,6 +68,7 @@ def parse_args(): parser.add_argument( "files", nargs="*", + type=Path, help="files or lists of files to process. use '-' to read from stdin", ) parser.add_argument( @@ -74,7 +78,7 @@ def parse_args(): type=str, help="set an arbitrary comment character (e.g. //)", ) - group.add_argument("-d", "--depth", type=int, help="maximum toc depth") + parser.add_argument("-d", "--depth", type=int, help="maximum toc depth") parser.add_argument( "-e", action="store", @@ -101,7 +105,7 @@ def parse_args(): "-o", action="store", dest="output_file", - type=str, + type=Path, help="print output to an arbitrary file", ) parser.add_argument( @@ -115,23 +119,26 @@ def parse_args(): return args -def get_files(args) -> list: +def get_files(args) -> list[Path]: # consider all files as lists if args.from_list: files = [] for fileList in args.files: - try: + # try: + if True: with open(fileList, "r") as list_content: for line in list_content.read().splitlines(): - if not line.startswith("#"): + if not line.startswith("#") and line != "": # glob expansion files += [ + # globMatch for globMatch in glob.glob(line, recursive=True) globMatch - for globMatch in glob.glob(line, recursive=True) + for globMatch in Path.cwd().glob(line) + if globMatch.exists() and globMatch.is_file() ] # cannot open that list - except BaseException: - print(f'Skipping list "{fileList}"', file=sys.stderr) + # except BaseException: + # print(f'Skipping list "{fileList}"', file=sys.stderr) # only consider the first file elif args.output_file: files = [args.files[0]] @@ -144,7 +151,7 @@ def get_files(args) -> list: # ################################ PROCESS FILE -def process_file(inputFile: str, args): +def process_file(inputFile: Path, args): # initialize instance t = Toc(inputFile) # set comment character and line numbers diff --git a/toc/toc.py b/toc/toc.py index 5456553..f18b054 100644 --- a/toc/toc.py +++ b/toc/toc.py @@ -40,33 +40,29 @@ # stderr import sys +# files +from pathlib import Path + # ################################################################ CLASSES class Toc: - def __init__( - self, - inputFile: str = "", - outputFile: str | None = None, - lineNumbers: bool = False, - character: str = "#", - ): - self.inputFile = "stdin" if str(inputFile) == "-" else str(inputFile) - self.outputFile = outputFile - self.extension = ( - self.inputFile.split(".")[-1].lower() if "." in self.inputFile else "" - ) - self.lineNumbers = lineNumbers - self.character = character - self.depth = 0 + def __init__(self, inputFile: Path): + print(f"inputFile: {inputFile}", file=sys.stderr) + self.inputFile: Path = inputFile + self.outputFile: Path | None = None + self.extension: str = self.inputFile.suffix.lower().replace(".", "") + self.lineNumbers: bool = False + self.updated: bool = False + self.character: str = "#" + self.depth: int = 0 self.err: str | None = None - self.updated = False self.innerTocBegin: str | None = None self.innerTocTitle: str | None = None self.innerTocEnd: str | None = None # n=2**(7−l), l=7−math.log(n,2) - self.levels = {64: 1, 32: 2, 16: 3, 8: 4, 4: 5, 2: 6} + self.levels: dict[int, int] = {64: 1, 32: 2, 16: 3, 8: 4, 4: 5, 2: 6} # ################################ PUBLIC METHODS @@ -131,11 +127,11 @@ def to_stdout(self) -> None: # ######## FILE - def to_file(self, output: str | None = None) -> None: + def to_file(self, output: Path | None = None) -> None: # if file has been specified, print there instead of the original file (useful for testing) if self.outputFile is None: self.outputFile = output if output else self.inputFile - if self.inputFile == "stdin": + if self.inputFile == Path("-"): print( "Cannot write to stdin", file=sys.stderr ) if self.err is None else None @@ -342,8 +338,8 @@ def _toc_prefix_suffix(self) -> tuple[list, list]: def _toc_header(self) -> list: # begin the toc with the file name, truncating it if necessary - _filename = self.inputFile.split("/")[-1] - if self.inputFile == "stdin": + _filename = self.inputFile.name + if self.inputFile == Path("-"): _truncated_filename = ( f"stdin.{self.extension}" if self.extension != "" else "stdin" ) @@ -653,7 +649,7 @@ def _read_file(self) -> str: # display alert for common errors _data = "" try: - if self.inputFile == "stdin": + if self.inputFile == Path("-"): _data = sys.stdin.read() else: with open(self.inputFile, "r") as f: