Coverage for bookbuilderpy/preprocessor_code.py: 81%
62 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-17 23:15 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-17 23:15 +0000
1"""A preprocessor for loading code."""
3from os.path import basename
4from typing import Final
6import bookbuilderpy.constants as bc
7from bookbuilderpy.format_python import preprocess_python
8from bookbuilderpy.logger import logger
9from bookbuilderpy.path import Path
10from bookbuilderpy.strings import (
11 enforce_non_empty_str_without_ws,
12 lines_to_str,
13)
14from bookbuilderpy.types import type_error
17def get_programming_language(path: str) -> str | None:
18 """
19 Get the programming language corresponding to a path.
21 :param path: the path to the source file
22 :return: a string identifying the programming language, or None if none
23 detected.
24 """
25 _, suffix = Path.split_prefix_suffix(basename(Path.path(path)))
26 suffix = suffix.lower()
27 if suffix == "py":
28 return bc.LANG_PYTHON
29 return bc.LANG_UNDEFINED
32def load_code(path: str, lines: str, labels: str, args: str) -> str:
33 """
34 Load a piece of code from the given path.
36 :param path: the path
37 :param lines: a line definition string
38 :param labels: a label definition string
39 :param args: a string of arguments to be passed to the formatter
40 :return: the code
41 """
42 src = Path.file(path)
43 logger(f"Now loading code from '{src}'.")
45 keep_lines: list[int] | None = None
46 if lines is not None:
47 if not isinstance(lines, str):
48 raise type_error(lines, "lines", str)
50 if len(lines) > 0:
51 keep_lines = []
52 for the_line in lines.split(","):
53 line = the_line.strip()
54 if "-" in line:
55 ab = line.split("-")
56 if len(ab) != 2:
57 raise ValueError(f"Invalid lines: {lines}.")
58 keep_lines.extend(range(int(ab[0]) - 1, int(ab[1])))
59 else:
60 keep_lines.append(int(line) - 1)
62 keep_labels: set[str] | None = None
63 if labels is not None:
64 if not isinstance(labels, str):
65 raise type_error(labels, "labels", str)
66 if len(labels) > 0:
67 keep_labels = set()
68 for label in labels.split(","):
69 ll = enforce_non_empty_str_without_ws(label.strip())
70 if ll in keep_labels:
71 raise ValueError(f"duplicate label: '{ll}'")
72 keep_labels.add(ll)
73 if len(keep_labels) <= 0:
74 raise ValueError(f"labels='{labels}'.")
76 arg_set: Final[set[str]] = set()
77 if args is not None:
78 if not isinstance(args, str):
79 raise type_error(args, "args", str)
80 if len(args) > 0:
81 for arg in args.split(","):
82 aa = enforce_non_empty_str_without_ws(arg.strip())
83 if aa in arg_set:
84 raise ValueError(f"duplicate argument: '{aa}'")
85 arg_set.add(aa)
87 text: Final[list[str]] = src.read_all_list()
88 if len(text) <= 0:
89 raise ValueError(f"File '{path}' is empty.")
91 if get_programming_language(path) == bc.LANG_PYTHON:
92 return preprocess_python(text, keep_lines, keep_labels, arg_set)
94 if keep_lines is None:
95 return lines_to_str([t.rstrip() for t in text])
97 return lines_to_str([text[i].rstrip() for i in keep_lines])