Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,5 @@ docs/_build

# IDEs
.idea

.eggs/
36 changes: 25 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
# Config file for automatic testing at travis-ci.org

language: python

python:
- "3.5"
- "3.4"
- "3.3"
- "3.2"
- "2.7"
- "2.6"
- "pypy"
matrix:
include:
- dist: xenial # Needed for Python 3.7
python: 3.7
language: python
- dist: xenial # Needed for Python 3.6
python: 3.6
language: python
- python: 3.5
language: python
- python: 3.4
language: python
- python: 3.3
language: python
- python: 3.2
language: python
- python: 2.7
language: python
- python: 2.6
language: python
- python: pypy
language: python
- python: pypy3
language: python

# command to install dependencies:
install: pip install mock
Expand All @@ -18,4 +32,4 @@ install: pip install mock
script: python setup.py test

# migrate to container-based travis.ci: http://docs.travis-ci.com/user/migrating-from-legacy
sudo: false
sudo: false
60 changes: 39 additions & 21 deletions configargparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,22 +265,7 @@ class ArgumentParser(argparse.ArgumentParser):
environment variables and .ini or .yaml-style config files.
"""

def __init__(self,
add_config_file_help=True,
add_env_var_help=True,
auto_env_var_prefix=None,
default_config_files=[],
ignore_unknown_config_file_keys=False,
config_file_parser_class=DefaultConfigFileParser,
args_for_setting_config_path=[],
config_arg_is_required=False,
config_arg_help_message="config file path",
args_for_writing_out_config_file=[],
write_out_config_file_arg_help_message="takes the current command line "
"args and writes them out to a config file at the given path, then "
"exits",
**kwargs
):
def __init__(self, *args, **kwargs):

"""Supports args of the argparse.ArgumentParser constructor
as **kwargs, as well as the following additional args.
Expand Down Expand Up @@ -331,11 +316,34 @@ def __init__(self,
write_out_config_file_arg_help_message: The help message to use for
the args in args_for_writing_out_config_file.
"""
# This is the only way to make positional args (tested in the argparse
# main test suite) and keyword arguments work across both Python 2 and
# 3. This could be refactored to not need extra local variables.
add_config_file_help = kwargs.pop('add_config_file_help', True)
add_env_var_help = kwargs.pop('add_env_var_help', True)
auto_env_var_prefix = kwargs.pop('auto_env_var_prefix', None)
default_config_files = kwargs.pop('default_config_files', [])
ignore_unknown_config_file_keys = kwargs.pop(
'ignore_unknown_config_file_keys', False)
config_file_parser_class = kwargs.pop('config_file_parser_class',
DefaultConfigFileParser)
args_for_setting_config_path = kwargs.pop(
'args_for_setting_config_path', [])
config_arg_is_required = kwargs.pop('config_arg_is_required', False)
config_arg_help_message = kwargs.pop('config_arg_help_message',
"config file path")
args_for_writing_out_config_file = kwargs.pop(
'args_for_writing_out_config_file', [])
write_out_config_file_arg_help_message = kwargs.pop(
'write_out_config_file_arg_help_message', "takes the current "
"command line args and writes them out to a config file at the "
"given path, then exits")

self._add_config_file_help = add_config_file_help
self._add_env_var_help = add_env_var_help
self._auto_env_var_prefix = auto_env_var_prefix

argparse.ArgumentParser.__init__(self, **kwargs)
argparse.ArgumentParser.__init__(self, *args, **kwargs)

# parse the additional args
if config_file_parser_class is None:
Expand Down Expand Up @@ -431,6 +439,7 @@ def parse_known_args(self, args = None, namespace = None,

# add env var settings to the commandline that aren't there already
env_var_args = []
nargs = False
actions_with_env_var_values = [a for a in self._actions
if not a.is_positional_arg and a.env_var and a.env_var in env_vars
and not already_on_command_line(args, a.option_strings)]
Expand All @@ -439,20 +448,23 @@ def parse_known_args(self, args = None, namespace = None,
value = env_vars[key]
# Make list-string into list.
if action.nargs or isinstance(action, argparse._AppendAction):
nargs = True
element_capture = re.match('\[(.*)\]', value)
if element_capture:
value = [val.strip() for val in element_capture.group(1).split(',') if val.strip()]
env_var_args += self.convert_item_to_command_line_arg(
action, key, value)

args = args + env_var_args
if nargs:
args = args + env_var_args
else:
args = env_var_args + args

if env_var_args:
self._source_to_settings[_ENV_VAR_SOURCE_KEY] = OrderedDict(
[(a.env_var, (a, env_vars[a.env_var]))
for a in actions_with_env_var_values])


# before parsing any config files, check if -h was specified.
supports_help_arg = any(
a for a in self._actions if isinstance(a, argparse._HelpAction))
Expand Down Expand Up @@ -484,6 +496,7 @@ def parse_known_args(self, args = None, namespace = None,

# add each config item to the commandline unless it's there already
config_args = []
nargs = False
for key, value in config_items.items():
if key in known_config_keys:
action = known_config_keys[key]
Expand All @@ -503,9 +516,14 @@ def parse_known_args(self, args = None, namespace = None,
if source_key not in self._source_to_settings:
self._source_to_settings[source_key] = OrderedDict()
self._source_to_settings[source_key][key] = (action, value)
if (action and action.nargs or
isinstance(action, argparse._AppendAction)):
nargs = True

args = args + config_args

if nargs:
args = args + config_args
else:
args = config_args + args

# save default settings for use by print_values()
default_settings = OrderedDict()
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def launch_http_server(directory):

setup(
name='ConfigArgParse',
version="0.14.0",
version="0.14.1",
description='A drop-in replacement for argparse that allows options to '
'also be set via config files and/or environment variables.',
long_description=long_description,
Expand Down
8 changes: 8 additions & 0 deletions tests/test_configargparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,14 @@ def test_FormatHelp(self):
'--flag \s*Flag help text'
)

def test_FormatHelpProg(self):
self.initParser('format_help_prog')
self.assertRegex(self.format_help(), 'usage: format_help_prog .*')

def test_FormatHelpProgLib(self):
parser = argparse.ArgumentParser('format_help_prog')
self.assertRegex(parser.format_help(), 'usage: format_help_prog .*')

class CustomClass(object):
def __init__(self, name):
self.name = name
Expand Down
11 changes: 10 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py26, py27, py32, py33, py34, py35
envlist = py26, py27, py32, py33, py34, py35, py36, py37, pypy, pypy3
# py34 # bug with virtualenv so tox doesn't work?


Expand Down Expand Up @@ -27,5 +27,14 @@ basepython=python3.4
[testenv:py35]
basepython=python3.5

[testenv:py36]
basepython=python3.6

[testenv:py37]
basepython=python3.7

[testenv:pypy]
basepython=pypy

[testenv:pypy3]
basepython=pypy3