From 0f3d256ebfe9e2f0adaecc96b8840d8d2328dfca Mon Sep 17 00:00:00 2001 From: Adam Porter Date: Wed, 30 Oct 2019 08:45:17 -0500 Subject: [PATCH] Add: parse-args function Closes #1719. --- NEWS.rst | 1 + docs/language/core.rst | 23 +++++++++++++++++++++++ hy/core/language.hy | 15 ++++++++++++++- tests/native_tests/core.hy | 9 +++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index 40bd19b..2053b1f 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -18,6 +18,7 @@ New Features * All augmented assignment operators (except `%=` and `^=`) now allow more than two arguments. * PEP 3107 and PEP 526 function and variable annotations are now supported. +* Added function ``parse-args`` which parses arguments with ``argparse``. Other Breaking Changes ------------------------------ diff --git a/docs/language/core.rst b/docs/language/core.rst index cabb420..6cb8c4d 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -786,6 +786,29 @@ Returns ``True`` if *x* is odd. Raises ``TypeError`` if => (odd? 0) False +.. _parse-args: + +parse-args +---------- + +Usage: ``(parse-args spec &optional args &kwargs parser-args)`` + +Return arguments namespace parsed from *args* or ``sys.argv`` with +:py:meth:`argparse.ArgumentParser.parse_args` according to *spec*. + +*spec* should be a list of arguments which will be passed to repeated +calls to :py:meth:`argparse.ArgumentParser.add_argument`. *parser-args* +may be a list of keyword arguments to pass to the +:py:class:`argparse.ArgumentParser` constructor. + +.. code-block:: hy + + => (parse-args [["strings" :nargs "+" :help "Strings"] + ["-n" "--numbers" :action "append" :type 'int :help "Numbers"]] + ["a" "b" "-n" "1" "-n" "2"] + :description "Parse strings and numbers from args") + Namespace(numbers=[1, 2], strings=['a', 'b']) + .. _partition-fn: partition diff --git a/hy/core/language.hy b/hy/core/language.hy index 80cba83..fa82185 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -391,6 +391,19 @@ Even objects with the __name__ magic will work." False (or a b))) +(defn parse-args [spec &optional args &kwargs parser-args] + "Return arguments namespace parsed from `args` or `sys.argv` with `argparse.ArgumentParser.parse-args` according to `spec`. + +`spec` should be a list of arguments to pass to repeated calls to +`argparse.ArgumentParser.add-argument`. `parser-args` may be a list +of keyword arguments to pass to the `argparse.ArgumentParser` +constructor." + (import argparse) + (setv parser (argparse.ArgumentParser #** parser-args)) + (for [arg spec] + (eval `(.add-argument parser ~@arg))) + (.parse-args parser args)) + (setv EXPORTS '[*map accumulate butlast calling-module calling-module-name chain coll? combinations comp complement compress constantly count cycle dec distinct @@ -399,6 +412,6 @@ Even objects with the __name__ magic will work." integer? integer-char? interleave interpose islice iterable? iterate iterator? juxt keyword keyword? last list? macroexpand macroexpand-1 mangle merge-with multicombinations name neg? none? nth - numeric? odd? partition permutations pos? product read read-str + numeric? odd? parse-args partition permutations pos? product read read-str remove repeat repeatedly rest reduce second some string? symbol? take take-nth take-while tuple? unmangle xor tee zero? zip-longest]) diff --git a/tests/native_tests/core.hy b/tests/native_tests/core.hy index b961f78..e5aad68 100644 --- a/tests/native_tests/core.hy +++ b/tests/native_tests/core.hy @@ -478,6 +478,15 @@ result['y in globals'] = 'y' in globals()") (assert-false (odd? 0)) (assert-requires-num odd?)) +(defn test-parse-args [] + "NATIVE: testing the parse-args function" + (setv parsed-args (parse-args [["strings" :nargs "+" :help "Strings"] + ["-n" "--numbers" :action "append" :type 'int :help "Numbers"]] + ["a" "b" "-n" "1" "-n" "2"] + :description "Parse strings and numbers from args")) + (assert-equal parsed-args.strings ["a" "b"]) + (assert-equal parsed-args.numbers [1 2])) + (defn test-partition [] "NATIVE: testing the partition function" (setv ten (range 10))