def test_overrides(): cfg = ConfigManager() # any sensible (and also our CI) test environment(s) should have this assert_in('user.name', cfg) # set cfg.set('user.name', 'myoverride', scope='override') assert_equal(cfg['user.name'], 'myoverride') # unset just removes override, not entire config cfg.unset('user.name', scope='override') assert_in('user.name', cfg) assert_not_equal('user.name', 'myoverride') # add # there is no initial increment cfg.add('user.name', 'myoverride', scope='override') assert_equal(cfg['user.name'], 'myoverride') # same as with add, not a list assert_equal(cfg['user.name'], 'myoverride') # but then there is cfg.add('user.name', 'myother', scope='override') assert_equal(cfg['user.name'], ['myoverride', 'myother']) # rename assert_not_in('ups.name', cfg) cfg.rename_section('user', 'ups', scope='override') # original variable still there assert_in('user.name', cfg) # rename of override in effect assert_equal(cfg['ups.name'], ['myoverride', 'myother']) # remove entirely by section cfg.remove_section('ups', scope='override') from datalad.utils import Path assert_not_in('ups.name', cfg, ( cfg._stores, cfg.overrides, ))
def test_obtain(path=None): ds = create(path) cfg = ConfigManager(ds) dummy = 'datalad.test.dummy' # we know nothing and we don't know how to ask assert_raises(RuntimeError, cfg.obtain, dummy) # can report known ones cfg.add(dummy, '5.3') assert_equal(cfg.obtain(dummy), '5.3') # better type assert_equal(cfg.obtain(dummy, valtype=float), 5.3) # don't hide type issues, float doesn't become an int magically assert_raises(ValueError, cfg.obtain, dummy, valtype=int) # inject some prior knowledge from datalad.interface.common_cfg import definitions as cfg_defs cfg_defs[dummy] = dict(type=float) # no we don't need to specify a type anymore assert_equal(cfg.obtain(dummy), 5.3) # but if we remove the value from the config, all magic is gone cfg.unset(dummy) # we know nothing and we don't know how to ask assert_raises(RuntimeError, cfg.obtain, dummy) # # test actual interaction # @with_testsui() def ask(): # fail on unknown dialog type assert_raises(ValueError, cfg.obtain, dummy, dialog_type='Rorschach_test') ask() # ask nicely, and get a value of proper type using the preconfiguration @with_testsui(responses='5.3') def ask(): assert_equal(cfg.obtain(dummy, dialog_type='question', text='Tell me'), 5.3) ask() # preconfigure even more, to get the most compact call cfg_defs[dummy]['ui'] = ('question', dict(text='tell me', title='Gretchen Frage')) @with_testsui(responses='5.3') def ask(): assert_equal(cfg.obtain(dummy), 5.3) ask() @with_testsui(responses='murks') def ask(): assert_raises(ValueError, cfg.obtain, dummy) ask() # fail to store when destination is not specified, will not even ask @with_testsui() def ask(): assert_raises(ValueError, cfg.obtain, dummy, store=True) ask() # but we can preconfigure it cfg_defs[dummy]['destination'] = 'broken' @with_testsui(responses='5.3') def ask(): assert_raises(ValueError, cfg.obtain, dummy, store=True) ask() # fixup destination cfg_defs[dummy]['destination'] = 'branch' @with_testsui(responses='5.3') def ask(): assert_equal(cfg.obtain(dummy, store=True), 5.3) ask() # now it won't have to ask again @with_testsui() def ask(): assert_equal(cfg.obtain(dummy), 5.3) ask() # wipe it out again cfg.unset(dummy) assert_not_in(dummy, cfg)
def test_something(path=None, new_home=None): # will refuse to work on dataset without a dataset assert_raises(ValueError, ConfigManager, source='branch') # now read the example config cfg = ConfigManager(GitRepo(opj(path, 'ds'), create=True), source='branch') assert_equal(len(cfg), 5) assert_in('something.user', cfg) # multi-value assert_equal(len(cfg['something.user']), 2) assert_equal(cfg['something.user'], ('name=Jane Doe', '[email protected]')) assert_true(cfg.has_section('something')) assert_false(cfg.has_section('somethingelse')) assert_equal(sorted(cfg.sections()), [u'onemore.complicated の beast with.dot', 'something']) assert_true(cfg.has_option('something', 'user')) assert_false(cfg.has_option('something', 'us?er')) assert_false(cfg.has_option('some?thing', 'user')) assert_equal(sorted(cfg.options('something')), ['empty', 'myint', 'novalue', 'user']) assert_equal(cfg.options(u'onemore.complicated の beast with.dot'), ['findme']) assert_equal(sorted(cfg.items()), [(u'onemore.complicated の beast with.dot.findme', '5.0'), ('something.empty', ''), ('something.myint', '3'), ('something.novalue', None), ('something.user', ('name=Jane Doe', '[email protected]'))]) assert_equal(sorted(cfg.items('something')), [('something.empty', ''), ('something.myint', '3'), ('something.novalue', None), ('something.user', ('name=Jane Doe', '[email protected]'))]) # by default get last value only assert_equal(cfg.get('something.user'), '[email protected]') # but can get all values assert_equal(cfg.get('something.user', get_all=True), ('name=Jane Doe', '[email protected]')) assert_raises(KeyError, cfg.__getitem__, 'somedthing.user') assert_equal( cfg.getfloat(u'onemore.complicated の beast with.dot', 'findme'), 5.0) assert_equal(cfg.getint('something', 'myint'), 3) assert_equal(cfg.getbool('something', 'myint'), True) # git demands a key without value at all to be used as a flag, thus True assert_equal(cfg.getbool('something', 'novalue'), True) assert_equal(cfg.get('something.novalue'), None) # empty value is False assert_equal(cfg.getbool('something', 'empty'), False) assert_equal(cfg.get('something.empty'), '') assert_equal(cfg.getbool('doesnot', 'exist', default=True), True) assert_raises(TypeError, cfg.getbool, 'something', 'user') # gitpython-style access assert_equal(cfg.get('something.myint'), cfg.get_value('something', 'myint')) assert_equal(cfg.get_value('doesnot', 'exist', default='oohaaa'), 'oohaaa') # weird, but that is how it is assert_raises(KeyError, cfg.get_value, 'doesnot', 'exist', default=None) # modification follows cfg.add('something.new', 'の') assert_equal(cfg.get('something.new'), u'の') # sections are added on demand cfg.add('unheard.of', 'fame') assert_true(cfg.has_section('unheard.of')) comp = cfg.items('something') cfg.rename_section('something', 'this') assert_true(cfg.has_section('this')) assert_false(cfg.has_section('something')) # direct comparison would fail, because of section prefix assert_equal(len(cfg.items('this')), len(comp)) # fail if no such section with swallow_logs(): assert_raises(CommandError, cfg.rename_section, 'nothere', 'irrelevant') assert_true(cfg.has_option('this', 'myint')) cfg.unset('this.myint') assert_false(cfg.has_option('this', 'myint')) # batch a changes cfg.add('mike.wants.to', 'know', reload=False) assert_false('mike.wants.to' in cfg) cfg.add('mike.wants.to', 'eat') assert_true('mike.wants.to' in cfg) assert_equal(len(cfg['mike.wants.to']), 2) # set a new one: cfg.set('mike.should.have', 'known') assert_in('mike.should.have', cfg) assert_equal(cfg['mike.should.have'], 'known') # set an existing one: cfg.set('mike.should.have', 'known better') assert_equal(cfg['mike.should.have'], 'known better') # set, while there are several matching ones already: cfg.add('mike.should.have', 'a meal') assert_equal(len(cfg['mike.should.have']), 2) # raises with force=False assert_raises(CommandError, cfg.set, 'mike.should.have', 'a beer', force=False) assert_equal(len(cfg['mike.should.have']), 2) # replaces all matching ones with force=True cfg.set('mike.should.have', 'a beer', force=True) assert_equal(cfg['mike.should.have'], 'a beer') # test deprecated 'where' interface and old 'dataset' (not 'branch') value # TODO: remove along with the removal of deprecated 'where' cfg.set('mike.should.have', 'wasknown', where='dataset') assert_equal(cfg['mike.should.have'], 'wasknown') assert_equal(cfg.get_from_source('dataset', 'mike.should.have'), 'wasknown') # fails unknown location assert_raises(ValueError, cfg.add, 'somesuch', 'shit', scope='umpalumpa') # very carefully test non-local config # so carefully that even in case of bad weather Yarik doesn't find some # lame datalad unittest sections in his precious ~/.gitconfig # Note: An easier way to test this, would be to just set GIT_CONFIG_GLOBAL # to point somewhere else. However, this is not supported by git before # 2.32. Hence, stick with changed HOME in this test, but be sure to unset a # possible GIT_CONFIG_GLOBAL in addition. patched_env = os.environ.copy() patched_env.pop('GIT_CONFIG_GLOBAL', None) patched_env.update(get_home_envvars(new_home)) with patch.dict('os.environ', dict(patched_env, DATALAD_SNEAKY_ADDITION='ignore'), clear=True): global_gitconfig = opj(new_home, '.gitconfig') assert (not exists(global_gitconfig)) globalcfg = ConfigManager() assert_not_in('datalad.unittest.youcan', globalcfg) assert_in('datalad.sneaky.addition', globalcfg) cfg.add('datalad.unittest.youcan', 'removeme', scope='global') assert (exists(global_gitconfig)) # it did not go into the dataset's config! assert_not_in('datalad.unittest.youcan', cfg) # does not monitor additions! globalcfg.reload(force=True) assert_in('datalad.unittest.youcan', globalcfg) with swallow_logs(): assert_raises(CommandError, globalcfg.unset, 'datalad.unittest.youcan', scope='local') assert (globalcfg.has_section('datalad.unittest')) globalcfg.unset('datalad.unittest.youcan', scope='global') # but after we unset the only value -- that section is no longer listed assert (not globalcfg.has_section('datalad.unittest')) assert_not_in('datalad.unittest.youcan', globalcfg) ok_file_has_content(global_gitconfig, "") cfg = ConfigManager(Dataset(opj(path, 'ds')), source='branch', overrides={'datalad.godgiven': True}) assert_equal(cfg.get('datalad.godgiven'), True) # setter has no effect cfg.set('datalad.godgiven', 'false') assert_equal(cfg.get('datalad.godgiven'), True)
def test_something(path, new_home): # will refuse to work on dataset without a dataset assert_raises(ValueError, ConfigManager, source='dataset') # now read the example config cfg = ConfigManager(Dataset(opj(path, 'ds')), source='dataset') assert_equal(len(cfg), 5) assert_in('something.user', cfg) # multi-value assert_equal(len(cfg['something.user']), 2) assert_equal(cfg['something.user'], ('name=Jane Doe', '[email protected]')) assert_true(cfg.has_section('something')) assert_false(cfg.has_section('somethingelse')) assert_equal(sorted(cfg.sections()), [u'onemore.complicated の beast with.dot', 'something']) assert_true(cfg.has_option('something', 'user')) assert_false(cfg.has_option('something', 'us?er')) assert_false(cfg.has_option('some?thing', 'user')) assert_equal(sorted(cfg.options('something')), ['empty', 'myint', 'novalue', 'user']) assert_equal(cfg.options(u'onemore.complicated の beast with.dot'), ['findme']) assert_equal(sorted(cfg.items()), [(u'onemore.complicated の beast with.dot.findme', '5.0'), ('something.empty', ''), ('something.myint', '3'), ('something.novalue', None), ('something.user', ('name=Jane Doe', '[email protected]'))]) assert_equal(sorted(cfg.items('something')), [('something.empty', ''), ('something.myint', '3'), ('something.novalue', None), ('something.user', ('name=Jane Doe', '[email protected]'))]) # always get all values assert_equal(cfg.get('something.user'), ('name=Jane Doe', '[email protected]')) assert_raises(KeyError, cfg.__getitem__, 'somedthing.user') assert_equal( cfg.getfloat(u'onemore.complicated の beast with.dot', 'findme'), 5.0) assert_equal(cfg.getint('something', 'myint'), 3) assert_equal(cfg.getbool('something', 'myint'), True) # git demands a key without value at all to be used as a flag, thus True assert_equal(cfg.getbool('something', 'novalue'), True) assert_equal(cfg.get('something.novalue'), None) # empty value is False assert_equal(cfg.getbool('something', 'empty'), False) assert_equal(cfg.get('something.empty'), '') assert_equal(cfg.getbool('doesnot', 'exist', default=True), True) assert_raises(TypeError, cfg.getbool, 'something', 'user') # gitpython-style access assert_equal(cfg.get('something.myint'), cfg.get_value('something', 'myint')) assert_equal(cfg.get_value('doesnot', 'exist', default='oohaaa'), 'oohaaa') # weired, but that is how it is assert_raises(KeyError, cfg.get_value, 'doesnot', 'exist', default=None) # modification follows cfg.add('something.new', 'の') assert_equal(cfg.get('something.new'), u'の') # sections are added on demand cfg.add('unheard.of', 'fame') assert_true(cfg.has_section('unheard.of')) comp = cfg.items('something') cfg.rename_section('something', 'this') assert_true(cfg.has_section('this')) assert_false(cfg.has_section('something')) # direct comparision would fail, because of section prefix assert_equal(len(cfg.items('this')), len(comp)) # fail if no such section with swallow_logs(): assert_raises(CommandError, cfg.rename_section, 'nothere', 'irrelevant') assert_true(cfg.has_option('this', 'myint')) cfg.unset('this.myint') assert_false(cfg.has_option('this', 'myint')) # batch a changes cfg.add('mike.wants.to', 'know', reload=False) assert_false('mike.wants.to' in cfg) cfg.add('mike.wants.to', 'eat') assert_true('mike.wants.to' in cfg) assert_equal(len(cfg['mike.wants.to']), 2) # set a new one: cfg.set('mike.should.have', 'known') assert_in('mike.should.have', cfg) assert_equal(cfg['mike.should.have'], 'known') # set an existing one: cfg.set('mike.should.have', 'known better') assert_equal(cfg['mike.should.have'], 'known better') # set, while there are several matching ones already: cfg.add('mike.should.have', 'a meal') assert_equal(len(cfg['mike.should.have']), 2) # raises with force=False assert_raises(CommandError, cfg.set, 'mike.should.have', 'a beer', force=False) assert_equal(len(cfg['mike.should.have']), 2) # replaces all matching ones with force=True cfg.set('mike.should.have', 'a beer', force=True) assert_equal(cfg['mike.should.have'], 'a beer') # fails unknown location assert_raises(ValueError, cfg.add, 'somesuch', 'shit', where='umpalumpa') # very carefully test non-local config # so carefully that even in case of bad weather Yarik doesn't find some # lame datalad unittest sections in his precious ~/.gitconfig with patch.dict('os.environ', { 'HOME': new_home, 'DATALAD_SNEAKY_ADDITION': 'ignore' }): global_gitconfig = opj(new_home, '.gitconfig') assert (not exists(global_gitconfig)) globalcfg = ConfigManager() assert_not_in('datalad.unittest.youcan', globalcfg) assert_in('datalad.sneaky.addition', globalcfg) cfg.add('datalad.unittest.youcan', 'removeme', where='global') assert (exists(global_gitconfig)) # it did not go into the dataset's config! assert_not_in('datalad.unittest.youcan', cfg) # does not monitor additions! globalcfg.reload(force=True) assert_in('datalad.unittest.youcan', globalcfg) with swallow_logs(): assert_raises(CommandError, globalcfg.unset, 'datalad.unittest.youcan', where='local') assert (globalcfg.has_section('datalad.unittest')) globalcfg.unset('datalad.unittest.youcan', where='global') # but after we unset the only value -- that section is no longer listed assert (not globalcfg.has_section('datalad.unittest')) assert_not_in('datalad.unittest.youcan', globalcfg) if external_versions['cmd:git'] < '2.18': # older versions leave empty section behind in the file ok_file_has_content(global_gitconfig, '[datalad "unittest"]', strip=True) # remove_section to clean it up entirely globalcfg.remove_section('datalad.unittest', where='global') ok_file_has_content(global_gitconfig, "") cfg = ConfigManager(Dataset(opj(path, 'ds')), source='dataset', overrides={'datalad.godgiven': True}) assert_equal(cfg.get('datalad.godgiven'), True) # setter has no effect cfg.set('datalad.godgiven', 'false') assert_equal(cfg.get('datalad.godgiven'), True)
def test_something(path, new_home): # read nothing, has nothing cfg = ConfigManager(dataset_only=True) assert_false(len(cfg)) # now read the example config cfg = ConfigManager(Dataset(opj(path, 'ds')), dataset_only=True) assert_equal(len(cfg), 3) assert_in('something.user', cfg) # multi-value assert_equal(len(cfg['something.user']), 2) assert_equal(cfg['something.user'], ('name=Jane Doe', '[email protected]')) assert_true(cfg.has_section('something')) assert_false(cfg.has_section('somethingelse')) assert_equal(sorted(cfg.sections()), [u'onemore.complicated の beast with.dot', 'something']) assert_true(cfg.has_option('something', 'user')) assert_false(cfg.has_option('something', 'us?er')) assert_false(cfg.has_option('some?thing', 'user')) assert_equal(sorted(cfg.options('something')), ['myint', 'user']) assert_equal(cfg.options(u'onemore.complicated の beast with.dot'), ['findme']) assert_equal( sorted(cfg.items()), [(u'onemore.complicated の beast with.dot.findme', '5.0'), ('something.myint', '3'), ('something.user', ('name=Jane Doe', '[email protected]'))]) assert_equal( sorted(cfg.items('something')), [('something.myint', '3'), ('something.user', ('name=Jane Doe', '[email protected]'))]) # always get all values assert_equal( cfg.get('something.user'), ('name=Jane Doe', '[email protected]')) assert_raises(KeyError, cfg.__getitem__, 'somedthing.user') assert_equal(cfg.getfloat(u'onemore.complicated の beast with.dot', 'findme'), 5.0) assert_equal(cfg.getint('something', 'myint'), 3) assert_equal(cfg.getbool('something', 'myint'), True) assert_equal(cfg.getbool('doesnot', 'exist', default=True), True) assert_raises(TypeError, cfg.getbool, 'something', 'user') # gitpython-style access assert_equal(cfg.get('something.myint'), cfg.get_value('something', 'myint')) assert_equal(cfg.get_value('doesnot', 'exist', default='oohaaa'), 'oohaaa') # weired, but that is how it is assert_raises(KeyError, cfg.get_value, 'doesnot', 'exist', default=None) # modification follows cfg.add('something.new', 'の') assert_equal(cfg.get('something.new'), u'の') # sections are added on demand cfg.add('unheard.of', 'fame') assert_true(cfg.has_section('unheard.of')) comp = cfg.items('something') cfg.rename_section('something', 'this') assert_true(cfg.has_section('this')) assert_false(cfg.has_section('something')) # direct comparision would fail, because of section prefix assert_equal(len(cfg.items('this')), len(comp)) # fail if no such section with swallow_logs(): assert_raises(CommandError, cfg.rename_section, 'nothere', 'irrelevant') assert_true(cfg.has_option('this', 'myint')) cfg.unset('this.myint') assert_false(cfg.has_option('this', 'myint')) # batch a changes cfg.add('mike.wants.to', 'know', reload=False) assert_false('mike.wants.to' in cfg) cfg.add('mike.wants.to', 'eat') assert_true('mike.wants.to' in cfg) assert_equal(len(cfg['mike.wants.to']), 2) # set a new one: cfg.set('mike.should.have', 'known') assert_in('mike.should.have', cfg) assert_equal(cfg['mike.should.have'], 'known') # set an existing one: cfg.set('mike.should.have', 'known better') assert_equal(cfg['mike.should.have'], 'known better') # set, while there are several matching ones already: cfg.add('mike.should.have', 'a meal') assert_equal(len(cfg['mike.should.have']), 2) # raises with force=False assert_raises(CommandError, cfg.set, 'mike.should.have', 'a beer', force=False) assert_equal(len(cfg['mike.should.have']), 2) # replaces all matching ones with force=True cfg.set('mike.should.have', 'a beer', force=True) assert_equal(cfg['mike.should.have'], 'a beer') # fails unknown location assert_raises(ValueError, cfg.add, 'somesuch', 'shit', where='umpalumpa') # very carefully test non-local config # so carefully that even in case of bad weather Yarik doesn't find some # lame datalad unittest sections in his precious ~/.gitconfig with patch.dict('os.environ', {'HOME': new_home, 'DATALAD_SNEAKY_ADDITION': 'ignore'}): global_gitconfig = opj(new_home, '.gitconfig') assert(not exists(global_gitconfig)) globalcfg = ConfigManager(dataset_only=False) assert_not_in('datalad.unittest.youcan', globalcfg) assert_in('datalad.sneaky.addition', globalcfg) cfg.add('datalad.unittest.youcan', 'removeme', where='global') assert(exists(global_gitconfig)) # it did not go into the dataset's config! assert_not_in('datalad.unittest.youcan', cfg) # does not monitor additions! globalcfg.reload(force=True) assert_in('datalad.unittest.youcan', globalcfg) with swallow_logs(): assert_raises( CommandError, globalcfg.unset, 'datalad.unittest.youcan', where='local') assert(globalcfg.has_section('datalad.unittest')) globalcfg.unset('datalad.unittest.youcan', where='global') # but after we unset the only value -- that section is no longer listed assert (not globalcfg.has_section('datalad.unittest')) assert_not_in('datalad.unittest.youcan', globalcfg) if external_versions['cmd:git'] < '2.18': # older versions leave empty section behind in the file ok_file_has_content(global_gitconfig, '[datalad "unittest"]', strip=True) # remove_section to clean it up entirely globalcfg.remove_section('datalad.unittest', where='global') ok_file_has_content(global_gitconfig, "") cfg = ConfigManager( Dataset(opj(path, 'ds')), dataset_only=True, overrides={'datalad.godgiven': True}) assert_equal(cfg.get('datalad.godgiven'), True) # setter has no effect cfg.set('datalad.godgiven', 'false') assert_equal(cfg.get('datalad.godgiven'), True)
def test_obtain(path): ds = create(path) cfg = ConfigManager(ds) dummy = 'datalad.test.dummy' # we know nothing and we don't know how to ask assert_raises(RuntimeError, cfg.obtain, dummy) # can report known ones cfg.add(dummy, '5.3') assert_equal(cfg.obtain(dummy), '5.3') # better type assert_equal(cfg.obtain(dummy, valtype=float), 5.3) # don't hide type issues, float doesn't become an int magically assert_raises(ValueError, cfg.obtain, dummy, valtype=int) # inject some prior knowledge from datalad.interface.common_cfg import definitions as cfg_defs cfg_defs[dummy] = dict(type=float) # no we don't need to specify a type anymore assert_equal(cfg.obtain(dummy), 5.3) # but if we remove the value from the config, all magic is gone cfg.unset(dummy) # we know nothing and we don't know how to ask assert_raises(RuntimeError, cfg.obtain, dummy) # # test actual interaction # @with_testsui() def ask(): # fail on unkown dialog type assert_raises(ValueError, cfg.obtain, dummy, dialog_type='Rorschach_test') ask() # ask nicely, and get a value of proper type using the preconfiguration @with_testsui(responses='5.3') def ask(): assert_equal( cfg.obtain(dummy, dialog_type='question', text='Tell me'), 5.3) ask() # preconfigure even more, to get the most compact call cfg_defs[dummy]['ui'] = ('question', dict(text='tell me', title='Gretchen Frage')) @with_testsui(responses='5.3') def ask(): assert_equal(cfg.obtain(dummy), 5.3) ask() @with_testsui(responses='murks') def ask(): assert_raises(ValueError, cfg.obtain, dummy) ask() # fail to store when destination is not specified, will not even ask @with_testsui() def ask(): assert_raises(ValueError, cfg.obtain, dummy, store=True) ask() # but we can preconfigure it cfg_defs[dummy]['destination'] = 'broken' @with_testsui(responses='5.3') def ask(): assert_raises(ValueError, cfg.obtain, dummy, store=True) ask() # fixup destination cfg_defs[dummy]['destination'] = 'dataset' @with_testsui(responses='5.3') def ask(): assert_equal(cfg.obtain(dummy, store=True), 5.3) ask() # now it won't have to ask again @with_testsui() def ask(): assert_equal(cfg.obtain(dummy), 5.3) ask() # wipe it out again cfg.unset(dummy) assert_not_in(dummy, cfg)