Skip to content

Commit

Permalink
Add DUCKARGS_COMMENT and DUCKARGS_PRINT environment variables
Browse files Browse the repository at this point in the history
  • Loading branch information
eriknyquist committed Oct 13, 2023
1 parent bb84be0 commit 74898db
Show file tree
Hide file tree
Showing 21 changed files with 179 additions and 11 deletions.
29 changes: 26 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.. contents:: **Table of Contents**

.. |duck| unicode:: 0x1F986

duckargs |duck|
===============
---------------

.. |tests_badge| image:: https://github.com/eriknyquist/duckargs/actions/workflows/tests.yml/badge.svg
.. |cov_badge| image:: https://github.com/eriknyquist/duckargs/actions/workflows/coverage.yml/badge.svg
Expand Down Expand Up @@ -42,12 +44,13 @@ The output of the above command looks like this:

.. code:: python
# Generated by duckargs, invoked with the following arguments:
# positional_arg1 positional_arg2 -i --int-val 4 -f 3.3 -f --file FILE -F --otherfile FILE -a -b -c
import argparse
def main():
parser = argparse.ArgumentParser(description='',
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('positional_arg1', help='a string')
Expand Down Expand Up @@ -102,6 +105,26 @@ Either of which will generate a line like this:

parser.add_argument('-f', '--filename', default='file', type=argparse.FileType(), help='a filename')

Environment variables
=====================

Some things can be configured by setting environment variables.

``DUCKARGS_PRINT``
##################

By default, ``duckargs`` generates a program that prints all provided arguments/options,
so that you can see all the corresponding attribute names on the object returned by ``argparse``.
If you want to disable this and generate programs with the print statements, set
``DUCKARGS_PRINT=0`` in your environment variables.

``DUCKARGS_COMMENT``
####################

By default, ``duckargs`` generates a program that prints a comment header at the top,
showing the arguments that ``duckargs`` was invoked with. If you want to disable this and
generate programs without the comment header, set ``DUCKARGS_COMMENT=0`` in your environment
variables.

Use duckargs in python code
===========================
Expand All @@ -127,7 +150,7 @@ an option ``-q --quiet`` with a required argument.
To avoid this, it is recommended to declare your positional arguments first (as in: ``python -m duckargs positional_arg -q --quiet``)

Contributions
-------------
=============

Contributions are welcome, please open a pull request at `<https://github.com/eriknyquist/duckargs/pulls>`_.
You will need to install packages required for development by doing ``pip install -r dev_requirements.txt``.
Expand Down
34 changes: 26 additions & 8 deletions duckargs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,14 @@
import os
import re

PYTHON_TEMPLATE = """# {0}
import argparse
PYTHON_TEMPLATE = """{0}import argparse
def main():
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
{1}
args = parser.parse_args()
{2}
args = parser.parse_args(){2}
if __name__ == "__main__":
main()
Expand Down Expand Up @@ -290,6 +286,28 @@ def generate_python_code(argv=sys.argv):
"""
processed_args = process_args(argv)
optlines = " " + "\n ".join([o.generate_code() for o in processed_args])
printlines = " " + "\n ".join([f"print(args.{o.var_name})" for o in processed_args])

printlines = ""
env_print = os.environ.get('DUCKARGS_PRINT', 1)
try:
env_print_int = int(env_print)
except ValueError:
raise RuntimeError("DUCKARGS_PRINT must be an integer")

if env_print_int > 0:
printlines += "\n\n " + "\n ".join([f"print(args.{o.var_name})" for o in processed_args])

comment = ""
env_comment = os.environ.get("DUCKARGS_COMMENT", 1)
try:
env_comment_int = int(env_comment)
except ValueError:
raise RuntimeError("DUCKARGS_COMMENT must be an integer")

if env_comment_int > 0:
comment = (f"# Generated by duckargs, invoked with the following arguments:\n# " +
' '.join(argv[1:]) + "\n\n")

CmdlineOpt.positional_count = 0
return PYTHON_TEMPLATE.format(' '.join(argv[1:]), optlines, printlines)

return PYTHON_TEMPLATE.format(comment, optlines, printlines)
1 change: 1 addition & 0 deletions tests/test_data/choices/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# pos1 pos2 -f -g -q --qefqaf op,ep,orp

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/env_all/args.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
duckargs positional_arg1 positional_arg2 -i --int-val 4 -f 3.3 -f --file FILE -F --otherfile FILE -a -b -c
20 changes: 20 additions & 0 deletions tests/test_data/env_all/expected_python.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import argparse

def main():
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument('positional_arg1', help='a string')
parser.add_argument('positional_arg2', help='a string')
parser.add_argument('-i', '--int-val', default=4, type=int, help='an int value')
parser.add_argument('-f', default=3.3, type=float, help='a float value')
parser.add_argument('-f', '--file', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-F', '--otherfile', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-a', action='store_true', help='a flag')
parser.add_argument('-b', action='store_true', help='b flag')
parser.add_argument('-c', action='store_true', help='c flag')
args = parser.parse_args()

if __name__ == "__main__":
main()

1 change: 1 addition & 0 deletions tests/test_data/env_comment/args.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
duckargs positional_arg1 positional_arg2 -i --int-val 4 -f 3.3 -f --file FILE -F --otherfile FILE -a -b -c
30 changes: 30 additions & 0 deletions tests/test_data/env_comment/expected_python.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import argparse

def main():
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument('positional_arg1', help='a string')
parser.add_argument('positional_arg2', help='a string')
parser.add_argument('-i', '--int-val', default=4, type=int, help='an int value')
parser.add_argument('-f', default=3.3, type=float, help='a float value')
parser.add_argument('-f', '--file', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-F', '--otherfile', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-a', action='store_true', help='a flag')
parser.add_argument('-b', action='store_true', help='b flag')
parser.add_argument('-c', action='store_true', help='c flag')
args = parser.parse_args()

print(args.positional_arg1)
print(args.positional_arg2)
print(args.int_val)
print(args.f)
print(args.file)
print(args.otherfile)
print(args.a)
print(args.b)
print(args.c)

if __name__ == "__main__":
main()

1 change: 1 addition & 0 deletions tests/test_data/env_print/args.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
duckargs positional_arg1 positional_arg2 -i --int-val 4 -f 3.3 -f --file FILE -F --otherfile FILE -a -b -c
23 changes: 23 additions & 0 deletions tests/test_data/env_print/expected_python.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by duckargs, invoked with the following arguments:
# positional_arg1 positional_arg2 -i --int-val 4 -f 3.3 -f --file FILE -F --otherfile FILE -a -b -c

import argparse

def main():
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument('positional_arg1', help='a string')
parser.add_argument('positional_arg2', help='a string')
parser.add_argument('-i', '--int-val', default=4, type=int, help='an int value')
parser.add_argument('-f', default=3.3, type=float, help='a float value')
parser.add_argument('-f', '--file', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-F', '--otherfile', default=None, type=argparse.FileType(), help='a filename')
parser.add_argument('-a', action='store_true', help='a flag')
parser.add_argument('-b', action='store_true', help='b flag')
parser.add_argument('-c', action='store_true', help='c flag')
args = parser.parse_args()

if __name__ == "__main__":
main()

1 change: 1 addition & 0 deletions tests/test_data/flags_only/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# -a -b -c -d -e -f -g -h

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/hex/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# -f --fff 0xabc -q 0x --test ox2

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/many_opts/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# pos1 pos2 pos3 pos4 pos5 pos6 pos7 pos8 pos9 pos10 -a --aye 5 -w --yyy -k 0.0 -l jkjkj -o --out -d --ede -v --vvv jfijfdsifj -s --ssss -z --zzzz -c --ccc jiji -b --bbb 8 -i --ii d -q --qqqqsdgvs -y -r

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/negative_hex/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# -0x44 -f --fell -0x235 -x -0x8

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/negative_int/args.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
duckargs -4 -f --ff -2 --blah -2343 -6
22 changes: 22 additions & 0 deletions tests/test_data/negative_int/expected_python.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by duckargs, invoked with the following arguments:
# -4 -f --ff -2 --blah -2343 -6

import argparse

def main():
parser = argparse.ArgumentParser(description='A command-line program generated by duckargs',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)

parser.add_argument('positional_arg0', type=int, help='an int value')
parser.add_argument('-f', '--ff', default=-2, type=int, help='an int value')
parser.add_argument('--blah', default=-2343, type=int, help='an int value')
parser.add_argument('positional_arg1', type=int, help='an int value')
args = parser.parse_args()

print(args.positional_arg0)
print(args.ff)
print(args.blah)
print(args.positional_arg1)

if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions tests/test_data/normalize_names/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# -a --test_1 5464 -b --test__-2 8 -j --j==j -g --lp++l pos-1 pos_2 pos_-_3

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/options_only/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# -a 4 -b --bbb 5.5 -t --tttt test -j srgsrh -k wergwshg

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/positional_only/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# pos1 pos2 pos3 pos4 pos5 pos6

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/positional_values/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# 0x 0x123 2.3 hello -r --ra FILE

import argparse
Expand Down
1 change: 1 addition & 0 deletions tests/test_data/readme_example/expected_python.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Generated by duckargs, invoked with the following arguments:
# positional_arg1 positional_arg2 -i --int-val 4 -f 3.3 -f --file FILE -F --otherfile FILE -a -b -c

import argparse
Expand Down
18 changes: 18 additions & 0 deletions tests/test_duckargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "test_data")

class TestDuckargs(unittest.TestCase):
def setUp(self):
# Set default env. var values
os.environ["DUCKARGS_PRINT"] = "1"
os.environ["DUCKARGS_COMMENT"] = "1"

def _run_test(self, test_dir_name):
test_dir_path = os.path.join(TEST_DATA_DIR, test_dir_name)
expected_python_path = os.path.join(test_dir_path, "expected_python.txt")
Expand Down Expand Up @@ -55,6 +60,19 @@ def test_negative_int(self):
def test_negative_hex(self):
self._run_test("negative_hex")

def test_env_print(self):
os.environ["DUCKARGS_PRINT"] = "0"
self._run_test("env_print")

def test_env_comment(self):
os.environ["DUCKARGS_COMMENT"] = "0"
self._run_test("env_comment")

def test_env_all(self):
os.environ["DUCKARGS_COMMENT"] = "0"
os.environ["DUCKARGS_PRINT"] = "0"
self._run_test("env_all")

def test_duplicate_names(self):
self.assertRaises(ValueError, generate_python_code, ['duckargs', '-a', '-a'])
self.assertRaises(ValueError, generate_python_code, ['duckargs', '-a', '-b', '-a'])
Expand Down

0 comments on commit 74898db

Please sign in to comment.