def test_config_of_configs():
    uploads = Config({
        'threads': 1,
        'db': {
            'user': '******',
        },
    })

    downloads = Config({
        'enabled': True,
        'tmp_dir': '/tmp',
    })

    uploads.threads.value = 5
    downloads.tmp_dir.value = '/tmp/downloads'

    config = Config({
        'uploads': uploads,
        'downloads': downloads,
    })

    assert config.uploads.threads.value == 5

    config.uploads.threads.value = 3
    assert uploads.threads.value == 3

    assert config.uploads.threads is uploads.threads
    assert config.downloads.enabled is downloads.enabled

    uploads.reset()
    assert config.uploads.threads.value == 1
示例#2
0
def test_item_value_changed_hook_not_called_when_resetting_a_not_set():
    config = Config({'a': Item()})

    @config.hooks.item_value_changed
    def item_value_changed(item, old_value, new_value):
        raise AssertionError('This should not have been called')

    config.reset()
    config.a.value = not_set
def test_item_reset_is_tracked():
    config = Config({'a': 'aaa'})
    config.a.value = 'bbb'

    with config.changeset_context() as ctx:
        config.a.value = 'ccc'
        assert len(ctx.values) == 1

        config.reset()
        assert len(ctx.values) == 1

    assert ctx.values[config.a] is not_set
示例#4
0
def test_reset_resets_values_to_defaults():
    config = Config({'x': Item(type=int), 'y': Item(default='YES')})

    config.x.value = 23
    config.y.value = 'NO'

    assert config.x.value == 23
    assert config.y.value == 'NO'

    config.reset()

    assert config.x.is_default
    assert config.y.value == 'YES'
def test_read_reads_multiple_files_in_order(tmpdir):
    m = Config({
        'a': {
            'x': Item(type=float),
            'y': 'aye',
        },
        'b': {
            'm': False,
            'n': Item(type=int),
        }
    })

    path1 = tmpdir.join('config1.ini').strpath
    path2 = tmpdir.join('config2.ini').strpath
    path3 = tmpdir.join('config3.ini').strpath

    # Empty file
    m.configparser.dump(path1)

    # Can load from one empty file
    m.configparser.load(path1)
    assert m.is_default

    m.a.x.value = 0.33
    m.b.n.value = 42
    m.configparser.dump(path2)

    # Can load from one non-empty file
    m.reset()
    m.configparser.load(path2)
    assert not m.is_default
    assert m.a.x.value == 0.33

    m.reset()
    m.a.x.value = 0.66
    m.b.m.value = 'YES'
    m.configparser.dump(path3)

    m.reset()
    m.configparser.load([path1, path2, path3])

    assert m.a.x.value == 0.66
    assert m.a.y.is_default
    assert m.b.m.value is True
    assert m.b.m.raw_str_value == 'YES'
    assert m.b.n.value == 42

    m.reset()
    m.configparser.load([path3, path2, path1])

    assert m.a.x.value == 0.33  # this is the only difference with the above order
    assert m.a.y.is_default
    assert m.b.m.value is True
    assert m.b.m.raw_str_value == 'YES'
    assert m.b.n.value == 42

    # Make sure multiple paths not supported in non-list syntax.
    with pytest.raises(TypeError):
        m.configparser.load(path3, path2, path1)
示例#6
0
def test_item_value_changed_hook():
    config = Config({'uploads': {
        'db': {
            'user': '******',
        }
    }})

    calls = []

    @config.hooks.item_value_changed
    def item_value_changed(old_value=None,
                           new_value=None,
                           item=None,
                           **kwargs):
        calls.append((item, old_value, new_value))

    assert calls == []

    config.reset()

    assert calls == []

    config.uploads.db.user.set('admin')

    assert len(calls) == 1
    assert calls[-1] == (config.uploads.db.user, not_set, 'admin')

    config.uploads.db.user.value = 'Administrator'

    assert len(calls) == 2
    assert calls[-1] == (config.uploads.db.user, 'admin', 'Administrator')

    config.load_values({'uploads': {'something_nonexistent': True}})
    assert len(calls) == 2

    config.load_values({'uploads': {
        'db': {
            'user': '******'
        }
    }},
                       as_defaults=True)
    assert len(calls) == 2

    config.load_values({'uploads': {'db': {'user': '******'}}})
    assert len(calls) == 3
    assert calls[-1] == (config.uploads.db.user, 'Administrator', 'NEW VALUE')
示例#7
0
def test_item_value_changed_hook_called_on_item_reset():
    config = Config({'a': 'aaa', 'b': 'bbb', 'c': Item()})
    calls = []

    @config.hooks.item_value_changed
    def item_value_changed(item, old_value, new_value):
        calls.append(item.name)

    assert len(calls) == 0

    config.reset()
    assert len(calls) == 0

    # Setting same value as default value triggers the event
    config.a.value = 'aaa'
    assert calls == ['a']

    # Setting same value as the custom value before triggers the event
    config.a.value = 'aaa'
    assert calls == ['a', 'a']

    # Actual reset
    config.reset()
    assert calls == ['a', 'a', 'a']
def test_tracking_of_tricky_change_and_no_change_situations():
    config = Config({'a': 'aaa'})

    # Set custom value that matches the default. Should be tracked.
    with config.changeset_context() as ctx:
        assert len(ctx.values) == 0

        config.a.value = 'aaa'
        assert len(ctx.values) == 1

        config.reset()
        assert len(ctx.values) == 0

    # No custom value set to start with
    with config.changeset_context() as ctx:
        assert len(ctx.values) == 0

        # Set custom value
        config.a.value = 'bbb'
        assert len(ctx.values) == 1
        assert ctx.values[config.a] == 'bbb'

        # Set custom value which matches default value -- it still is a change.
        config.a.value = 'aaa'
        assert len(ctx.values) == 1
        assert ctx.values[config.a] == 'aaa'

        config.reset()
        assert len(ctx.values) == 0

    # Have a custom value to start with
    config.a.value = 'ccc'
    with config.changeset_context() as ctx:

        # Make one change
        config.a.value = 'ddd'
        assert len(ctx.values) == 1
        assert ctx.values[config.a] == 'ddd'

        # Change back to the original value (within this context), should result in no changes
        config.a.value = 'ccc'
        assert len(ctx.values) == 0

        # Reset still results in a change within this context.
        config.reset()
        assert len(ctx.values) == 1
        assert ctx.values[config.a] == not_set
示例#9
0
def test_nested_config():
    """
    This demonstrates how an application config can be created from multiple
    sections (which in turn can be created from others).
    """

    # Declaration of a config section may be a plain dictionary
    db_config = {
        'host': 'localhost',
        'user': '******',
        'password': '******',
    }

    # Or, it may be an already functional instance of Config
    server_config = Config({
        'port': 8080,
    })

    #
    # All these sections can be combined into one config:
    #
    config = Config({
        'db': db_config,
        'server': server_config,
        'greeting':
        'Hello',  # and you can have plain config items next to sections
    })

    # You can load values
    assert config.greeting.value == 'Hello'

    # Your original schemas are safe -- db_config dictionary won't be changed
    config.db.user.value = 'root'
    assert config.db.user.value == 'root'
    assert db_config['user'] == 'admin'

    # You can also change values by reading them from a dictionary.
    # Unknown names will be ignored unless you pass as_defaults=True
    # but in that case you will overwrite any previously existing items.
    config.load_values({
        'greeting': 'Good morning!',
        'comments': {
            'enabled': False
        }
    })
    assert config.greeting.value == 'Good morning!'
    assert 'comments' not in config

    # You can check if config value is the default value
    assert not config.db.user.is_default
    assert config.server.port.is_default

    # Or if it has any value at all
    assert config.server.port.has_value

    # Iterate over all items (recursively)
    all = dict(config.iter_items(recursive=True))
    assert all[('db', 'host')] is config.db.host
    assert all[('server', 'port')] is config.server.port

    # Export all values
    config_dict = config.dump_values()
    assert config_dict['db'] == {
        'host': 'localhost',
        'user': '******',
        'password': '******'
    }

    # Each section is a Config instance too, so you can export those separately too:
    assert config.server.dump_values() == config_dict['server']

    # You can reset individual items to their default values
    assert config.db.user.value == 'root'
    config.db.user.reset()
    assert config.db.user.value == 'admin'

    # Or sections
    config.db.user.value = 'root_again'
    assert config.db.user.value == 'root_again'
    config.db.reset()
    assert config.db.user.value == 'admin'

    # Or you can reset all configuration and you can make sure all values match defaults
    assert not config.is_default
    config.reset()
    assert config.is_default