Skip to content

Instantly share code, notes, and snippets.

@podhmo
Last active August 15, 2018 15:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save podhmo/ef969b6624c945746b59af01601c57da to your computer and use it in GitHub Desktop.
Save podhmo/ef969b6624c945746b59af01601c57da to your computer and use it in GitHub Desktop.
import ascommand
@ascommand.as_command
def run(*, x: int, y: int):
print(f"{x} + {y} = {x + y}")
def run(*, x: int, y: int):
print(f"{x} + {y} = {x + y}")
def main():
import argparse
parser = argparse.ArgumentParser(description=None)
parser.print_usage = parser.print_help
parser.add_argument('-x', required=True)
parser.add_argument('-y', required=True)
args = parser.parse_args()
run(**vars(args))
if __name__ == '__main__':
main()
$ python 02*.py -h
usage: 02ascommand-or-expose.py [-h] [--expose] -x X -y Y

optional arguments:
  -h, --help  show this help message and exit
  --expose
  -x X
  -y Y

$ python 02*.py -x 10 -y 20
10 + 20 = 1020

$ python 02*.py --expose


def run(*, x: int, y: int):
    print(f"{x} + {y} = {x + y}")



def main():
    import argparse
    parser = argparse.ArgumentParser(description=None)
    parser.print_usage = parser.print_help
    parser.add_argument('-x', required=True)
    parser.add_argument('-y', required=True)
    args = parser.parse_args()
    run(**vars(args))


if __name__ == '__main__':
    main()

$ python 03*.py -x 10 -y 20
10 + 20 = 1020
import sys
import inspect
import argparse
import re
class FakeArgumentParser:
def __init__(self, fn, *args, history=None, **kwargs):
self.fn = fn
self.history = history or [{"name": "__init__", "args": args, "kwargs": kwargs}]
def __getattr__(self, name):
self.history.append({"name": name})
return self
def __call__(self, *args, **kwargs):
latest = self.history[-1]
assert "args" not in latest
latest["args"] = args
latest["kwargs"] = kwargs
def parse_args(self, *args, **kwargs):
self.history.append({"name": "parse_args", "args": args, "kwargs": kwargs})
from prestring.python import Module, LazyArgumentsAndKeywords
def _make_call_stmt(history, default=""):
name = history["name"]
if name == "__init__":
name = default
kwargs = {k: repr(v) for k, v in history["kwargs"].items()}
args = [repr(v) for v in history["args"]]
return f"{name}({LazyArgumentsAndKeywords(args, kwargs)})"
m = Module()
m.sep()
with m.def_("main"):
m.import_("argparse")
m.stmt(f"parser = argparse.ArgumentParser{_make_call_stmt(self.history[0])}")
m.stmt("parser.print_usage = parser.print_help")
for x in self.history[1:-1]:
m.stmt(f"parser.{_make_call_stmt(x)}")
m.stmt(f"args = parser.{_make_call_stmt(self.history[-1])}")
m.stmt(f"{self.fn.__name__}(**vars(args))")
with m.if_("__name__ == '__main__'"):
m.stmt("main()")
with open(inspect.getsourcefile(self.fn)) as rf:
source = rf.read()
rx = re.compile("(?:@([\S]+\.)?as_command.*|^.*import ascommand.*)\n", re.MULTILINE)
exposed = rx.sub("", "".join(source))
print(exposed)
print(m)
sys.exit(0)
def as_command(fn=None, argv=None, level=2):
def call(fn, level=1, argv=argv):
frame = sys._getframe(level)
name = frame.f_globals["__name__"]
if name == "__main__":
argspec = inspect.getfullargspec(fn)
if "--expose" in (argv or sys.argv):
parser = FakeArgumentParser(fn, description=fn.__doc__)
else:
parser = argparse.ArgumentParser(description=fn.__doc__)
parser.add_argument("--expose", action="store_true")
parser.print_usage = parser.print_help
for k in argspec.kwonlyargs:
parser.add_argument(
f'{"-" if len(k) <= 1 else "--"}{k.replace("_", "-")}', required=True
)
args = parser.parse_args(argv)
params = vars(args).copy()
params.pop("expose")
return fn(**params)
else:
return fn
if fn is None:
return call
else:
return call(fn, level=level, argv=argv)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment