Skip to content

Commit

Permalink
use subclassing instead of keyword arguments for Section
Browse files Browse the repository at this point in the history
  • Loading branch information
nihlaeth committed Feb 15, 2017
1 parent 00a03e6 commit b920b68
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 291 deletions.
59 changes: 33 additions & 26 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,23 @@ Simple configuration example
application = "my_application"
author = "me"
general = Section(
name=StringOption(
class GeneralSection(Section):
"""General information."""
name = StringOption(
doc="your name",
default="unknown person"),
age=IntegerOption(
default="unknown person")
age = IntegerOption(
doc="your age",
required=True))
address = Section(
street=StringOption(
required=True)
general = GeneralSection()
class AddressSection(Section):
"""shipping address"""
street = StringOption(
doc="street including house number",
required=True),
city=StringOption(required=True),
required=False,
doc="shipping address")
required=True)
city = StringOption(required=True)
address = AddressSection(required=False)
if __name__ == "__main__":
CONFIG = MyConfig()
Expand Down Expand Up @@ -112,13 +115,13 @@ Command line use without required value:
$ python examples/simple_example.py
Traceback (most recent call last):
File "examples/simple_example.py", line 26, in <module>
File "examples/simple_example.py", line 29, in <module>
CONFIG = MyConfig()
File "/git/user_config/user_config/user_config/__init__.py", line 541, in __init__
File "/git/user_config/user_config/user_config/__init__.py", line 622, in __init__
self._elements[element].validate_data(self._data)
File "/git/user_config/user_config/user_config/__init__.py", line 322, in validate_data
File "/git/user_config/user_config/user_config/__init__.py", line 464, in validate_data
self._elements[element].validate_data(self._data)
File "/git/user_config/user_config/user_config/__init__.py", line 216, in validate_data
File "/git/user_config/user_config/user_config/__init__.py", line 380, in validate_data
self.element_name))
user_config.MissingData: no value was provided for required option age
Expand All @@ -136,28 +139,32 @@ Generate configuration file:
$ python examples/simple_example.py --generate-config
## This will be displayed in the configuration documentation.
[general]
## General information.
## your name
# name = unknown person
name = tamara
## your age
## REQUIRED
# age =
age =
[address]
## shipping address
## OPTIONAL_SECTION
## REQUIRED
# city =
city =
## street including house number
## REQUIRED
# street =
street =
[general]
## your age
## REQUIRED
# age =
age =
# city =
city =
## your name
# name = unknown person
Documentation
=============
Expand Down
25 changes: 14 additions & 11 deletions examples/simple_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@ class MyConfig(Config):

application = "my_application"
author = "me"
general = Section(
name=StringOption(

class GeneralSection(Section):
"""General information."""
name = StringOption(
doc="your name",
default="unknown person"),
age=IntegerOption(
default="unknown person")
age = IntegerOption(
doc="your age",
required=True))
address = Section(
street=StringOption(
required=True)
general = GeneralSection()
class AddressSection(Section):
"""shipping address"""
street = StringOption(
doc="street including house number",
required=True),
city=StringOption(required=True),
required=False,
doc="shipping address")
required=True)
city = StringOption(required=True)
address = AddressSection(required=False)

if __name__ == "__main__":
CONFIG = MyConfig()
Expand Down
82 changes: 42 additions & 40 deletions tests/test_config_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,17 +218,22 @@ def test_parser(self):
config_element.extract_data_from_parser(arguments, data)
assert data['all_good'] is True

# pylint: disable=missing-docstring,function-redefined,attribute-defined-outside-init
class EmptySection(Section):

pass

class TestSection(object):

def test_init(self):
section = Section(default=42)
assert section.get_default() is section
section = Section(default=None)
assert section.has_default()
assert len(section) == 0
with pytest.raises(AttributeError):
section = Section(keyword="not a config element")
section = Section(name=StringOption(default="test"))
empty_section = EmptySection()
assert empty_section.has_default()
assert empty_section.get_default() is empty_section
assert len(empty_section) == 0

class MySection(Section):
name = StringOption(default="test")
section = MySection()
section.get_default()

# test map methods
Expand All @@ -254,59 +259,56 @@ def test_init(self):

def test_incomplete_count(self):
# test optional section
section = Section(
required=False,
one=IntegerOption(),
two=IntegerOption(required=False))
section.get_default()
section.element_name = "section"
class MySection(Section):
one = IntegerOption()
two = IntegerOption(required=False)
optional_section = MySection(required=False)
optional_section.get_default()
optional_section.element_name = "section"
parser = argparse.ArgumentParser(prog="test application")
section.construct_parser(parser)
optional_section.construct_parser(parser)

# missing required value
arguments = vars(parser.parse_args([]))
section.extract_data_from_parser(arguments, None)
section.validate_data(None)
assert section.incomplete_count == 1
optional_section.extract_data_from_parser(arguments, None)
optional_section.validate_data(None)
assert optional_section.incomplete_count == 1

# missing required value, optional value provided
arguments = vars(parser.parse_args(['--two', '42']))
section.extract_data_from_parser(arguments, None)
section.validate_data(None)
assert section.incomplete_count == 1
optional_section.extract_data_from_parser(arguments, None)
optional_section.validate_data(None)
assert optional_section.incomplete_count == 1

# required value provided
arguments = vars(parser.parse_args(['--one', '5']))
section.extract_data_from_parser(arguments, None)
section.validate_data(None)
assert section.incomplete_count == 0
optional_section.extract_data_from_parser(arguments, None)
optional_section.validate_data(None)
assert optional_section.incomplete_count == 0

# test required section
section = Section(
required=True,
one=IntegerOption(),
two=IntegerOption(required=False))
section.get_default()
section.element_name = "section"
required_section = MySection(required=True)
required_section.get_default()
required_section.element_name = "section"
parser = argparse.ArgumentParser(prog="test application")
section.construct_parser(parser)
required_section.construct_parser(parser)

# missing required value
arguments = vars(parser.parse_args([]))
section.extract_data_from_parser(arguments, None)
required_section.extract_data_from_parser(arguments, None)
with pytest.raises(MissingData):
section.validate_data(None)
assert section.incomplete_count == 0
required_section.validate_data(None)
assert required_section.incomplete_count == 0

# missing required value, optional value provided
arguments = vars(parser.parse_args(['--two', '42']))
section.extract_data_from_parser(arguments, None)
required_section.extract_data_from_parser(arguments, None)
with pytest.raises(MissingData):
section.validate_data(None)
assert section.incomplete_count == 0
required_section.validate_data(None)
assert required_section.incomplete_count == 0

# required value provided
arguments = vars(parser.parse_args(['--one', '5']))
section.extract_data_from_parser(arguments, None)
section.validate_data(None)
assert section.incomplete_count == 0
required_section.extract_data_from_parser(arguments, None)
required_section.validate_data(None)
assert required_section.incomplete_count == 0

0 comments on commit b920b68

Please sign in to comment.