src/latex_include/main.py

latexInclude(inFile, outFile, includeDir=None)

Start recursively resolving inputs/includes

Parameters:
  • inFile (TextIO) –

    An open read text file object to read input LaTeX code from

  • outFile (TextIO) –

    An open write text file object to write resolved LaTeX code to

  • includeDir (Path | str | None, default: None ) –

    Optional dir to resolve includes from. If omitted the current dir is used.

Source code in src/latex_include/main.py
107
108
109
110
111
112
113
114
115
116
117
118
def latexInclude(inFile:typing.TextIO, outFile:typing.TextIO, includeDir:pl.Path|str|None=None) -> None:
    """Start recursively resolving inputs/includes

    Args:
        inFile:     An open read text file object to read input LaTeX code from
        outFile:    An open write text file object to write resolved LaTeX code to
        includeDir: Optional dir to resolve includes from. If omitted the current
                    dir is used.
    """
    if not includeDir:
        includeDir = pl.Path.cwd()
    _recursion(inFile, outFile, pl.Path(includeDir))

latexIncludeFiles(inPath, outPath=None, overwrite=False)

Open files and call latexInclude with them using inPath's parent as includeDir

Both files can be given as pathlib.Path or string.

We require inPath instead of defaulting to stdin, because we need its directory to resolve relative input/include paths in the LaTeX code

Parameters:
  • inPath (Path | str) –

    path of input file

  • outPath (Path | str | None, default: None ) –

    optional name of output file, if omitted stdout is used instead

  • overwrite (bool, default: False ) –

    overwrite existing output file if True

Raises:
  • OSError

    If a file cannot be opened.

  • FileNotFoundError

    If inPath is not found.

  • FileExistsError

    If outPath exists and overwrite is False.

Note

FileNotFoundError and FileExistsError are specializations of OSError, so catch them before OSError.

Source code in src/latex_include/main.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
def latexIncludeFiles(inPath:pl.Path|str, outPath:pl.Path|str|None=None, overwrite:bool=False) -> None:
    """Open files and call `latexInclude` with them using `inPath`'s parent as `includeDir`

    Both files can be given as `pathlib.Path` or string.

    We require `inPath` instead of defaulting to `stdin`, because we need
    its directory to resolve relative input/include paths in the LaTeX code

    Args:
        inPath:    path of input file
        outPath:   optional name of output file, if omitted `stdout` is used instead
        overwrite: overwrite existing output file if `True`

    Raises:
        OSError:           If a file cannot be opened.
        FileNotFoundError: If `inPath` is not found.
        FileExistsError:   If `outPath` exists and `overwrite` is `False`.

    Note:
        `FileNotFoundError` and `FileExistsError` are specializations of `OSError`,
        so catch them before `OSError`.
    """
    inPath = pl.Path(inPath)
    if not inPath.is_file():
        raise FileNotFoundError(inPath)

    inPathAbs = inPath.absolute()
    if outPath:
        # Mode 'x' raises FileExistsError if file exists
        mode = 'w' if overwrite else 'x'
        outPathAbs = pl.Path(outPath).absolute()
        output:contextlib.AbstractContextManager[typing.TextIO] = contextlib.closing(outPathAbs.open(mode))
    else:
        output = contextlib.nullcontext(sys.stdout)

    with inPathAbs.open() as inFile:
        with output as outFile:
            latexInclude(inFile, outFile, inPathAbs.parent)

main()

Called from command line

Parses command line for input and output and calls latexIncludeFiles with them.

If output exists an additional command line flag is required to overwrite it.

Source code in src/latex_include/main.py
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def main() -> None:
    """Called from command line

    Parses command line for input and output and calls `latexIncludeFiles` with them.

    If output exists an additional command line flag is required to overwrite it.
    """
    parser = argparse.ArgumentParser(description="Resolve input/include commands in a LaTeX file to a single file")

    # See latexIncludeFiles documentation, why --input is required
    parser.add_argument('-i', '--input', required=True, type=pl.Path, help="Main LaTeX file to resolve")
    parser.add_argument('-o', '--output', type=pl.Path, help="Output file, default is stdout")
    parser.add_argument('-w', '--overwrite', action='store_true', help="Silently overwrite existing diff (default: %(default)s)")
    parser.add_argument('--version', action='version', version=importlib.metadata.version('latex-include'), help="Show version number and exit")
    args = parser.parse_args()

    try:
        latexIncludeFiles(args.input, args.output, overwrite=args.overwrite)
    except FileNotFoundError as ex:
        print(f"Input file not found: {ex}")
        exit(1)
    except FileExistsError as ex:
        print(f"Output exists. Delete it or set option --overwrite (-w) to overwrite it: {ex}")
        exit(1)
    except OSError as ex:
        ic(ex)
        print(f"Cannot open input or output file: {ex}")
        exit(1)