Skip to content

Instantly share code, notes, and snippets.

@mara004
Last active January 26, 2026 23:58
Show Gist options
  • Select an option

  • Save mara004/ec32b465789f67ea086720f8c66eb878 to your computer and use it in GitHub Desktop.

Select an option

Save mara004/ec32b465789f67ea086720f8c66eb878 to your computer and use it in GitHub Desktop.
Wrap a python module's CLI entrypoint with argfiles support
#! /usr/bin/env python3
# SPDX-FileCopyrightText: 2026 mara004 <geisserml@gmail.com>
# SPDX-License-Identifier: BSD-2-Clause
import sys
import shlex
from pathlib import Path
from importlib import import_module
from importlib.metadata import entry_points
def _read_argfiles(argv, parents):
#print(argv, parents)
for arg in argv:
if arg.startswith("@"):
argfile_path = Path(arg[1:]).expanduser().resolve()
if argfile_path in parents:
raise RuntimeError("self-includes are prohibited (would be infinite recursion)")
argfile_content = argfile_path.read_text().strip()
for l in argfile_content.split("\n"):
parents.append(argfile_path)
try:
yield from _read_argfiles(shlex.split(l), parents)
finally:
parents.pop() #popped = ...
#assert popped is argfile_path
else:
yield arg
def main():
if sys.argv[1] in ("-h", "--help"):
print(f"Usage: {sys.argv[0]} MODNAME ARGFILE_ARGS", file=sys.stderr)
return
modname = sys.argv[1]
ep, = entry_points(group="console_scripts", name=modname)
modpath, funcname = ep.value.rsplit(":", maxsplit=1)
# list slicing copies
parents = []
argv_iter = _read_argfiles(sys.argv[2:], parents)
sys.argv.clear()
sys.argv.append(modname)
sys.argv.extend(argv_iter)
#assert not parents # len 0
module = import_module(modpath)
func = getattr(module, funcname)
func()
if __name__ == "__main__":
main()
@mara004
Copy link
Author

mara004 commented Apr 28, 2025

See also ctypesgen/ctypesgen#223 (comment) (thread) for background.

@mara004
Copy link
Author

mara004 commented Jul 4, 2025

todo: a ValueError would perhaps fit better than a RuntimeError for the recursive includes

@mara004
Copy link
Author

mara004 commented Jan 25, 2026

Another idea: we could change parents to a list (created in main()) and use append/pop.
This may avoid the tuple re-creations parents=(*parents, argfile_path).

@mara004
Copy link
Author

mara004 commented Jan 26, 2026

Done, I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment