Example #1
0
def test_settings_env_variables_do_not_write_to_disk(tmp_path, monkeypatch):

    # create a settings file with light theme
    data = "appearance:\n   theme: light"
    fake_path = tmp_path / 'fake_path.yml'
    fake_path.write_text(data)

    # make sure they wrote correctly
    disk_settings = fake_path.read_text()
    assert 'theme: light' in disk_settings
    # make sure they load correctly
    assert NapariSettings(fake_path).appearance.theme == "light"

    # now load settings again with an Env-var override
    monkeypatch.setenv('NAPARI_APPEARANCE_THEME', 'dark')
    settings = NapariSettings(fake_path)
    # make sure the override worked, and save again
    assert settings.appearance.theme == 'dark'
    # data from the config file is still "known"
    assert settings._config_file_settings['appearance']['theme'] == 'light'
    # but we know what came from env vars as well:
    assert settings.env_settings()['appearance']['theme'] == 'dark'

    # when we save it shouldn't use environment variables and it shouldn't
    # have overriden our non-default value of `theme: light`
    settings.save()
    disk_settings = fake_path.read_text()
    assert 'theme: light' in disk_settings

    # and it's back if we reread without the env var override
    monkeypatch.delenv('NAPARI_APPEARANCE_THEME')
    assert NapariSettings(fake_path).appearance.theme == "light"
Example #2
0
def test_no_save_path():
    """trying to save without a config path is an error"""
    s = NapariSettings(config_path=None)
    assert s.config_path is None

    with pytest.raises(ValueError):
        # the original `save()` method is patched in conftest.fresh_settings
        # so we "unmock" it here to assert the failure
        NapariSettings.__original_save__(s)  # type: ignore
Example #3
0
def test_settings_env_variables(monkeypatch):
    assert NapariSettings(None).appearance.theme == 'dark'
    # NOTE: this was previously tested as NAPARI_THEME
    monkeypatch.setenv('NAPARI_APPEARANCE_THEME', 'light')
    assert NapariSettings(None).appearance.theme == 'light'

    # can also use json
    assert NapariSettings(None).application.first_time is True
    # NOTE: this was previously tested as NAPARI_THEME
    monkeypatch.setenv('NAPARI_APPLICATION', '{"first_time": "false"}')
    assert NapariSettings(None).application.first_time is False
Example #4
0
def test_settings_load_invalid_type(tmp_path, caplog):
    # The invalid data will be replaced by the default value
    data = "appearance:\n   theme: 1"
    fake_path = tmp_path / 'fake_path.yml'
    fake_path.write_text(data)
    assert NapariSettings(fake_path).application.save_window_geometry is True
    assert 'Validation errors in config file' in str(caplog.records[0])
Example #5
0
def test_settings_load_strict(tmp_path, monkeypatch):
    # use Config.strict_config_check to enforce good config files
    monkeypatch.setattr(NapariSettings.__config__, 'strict_config_check', True)
    data = "appearance:\n   theme: 1"
    fake_path = tmp_path / 'fake_path.yml'
    fake_path.write_text(data)
    with pytest.raises(pydantic.ValidationError):
        NapariSettings(fake_path)
Example #6
0
def test_settings_to_dict_no_env(monkeypatch):
    """Test that exclude_env works to exclude variables coming from the env."""
    s = NapariSettings(None, appearance={'theme': 'light'})
    assert s.dict()['appearance']['theme'] == 'light'
    assert s.dict(exclude_env=True)['appearance']['theme'] == 'light'

    monkeypatch.setenv("NAPARI_APPEARANCE_THEME", 'light')
    s = NapariSettings(None)
    assert s.dict()['appearance']['theme'] == 'light'
    assert 'theme' not in s.dict(exclude_env=True).get('appearance', {})
Example #7
0
def test_settings_load_invalid_key(tmp_path, monkeypatch):
    # The invalid key will be removed

    fake_path = tmp_path / 'fake_path.yml'
    data = """
    application:
       non_existing_key: [1, 2]
       first_time: false
    """
    fake_path.write_text(data)

    monkeypatch.setattr(os, 'environ', {})
    s = NapariSettings(fake_path)
    assert getattr(s, "non_existing_key", None) is None
    s.save()
    text = fake_path.read_text()
    # removed bad key
    assert safe_load(text) == {'application': {'first_time': False}}
Example #8
0
def test_settings_load_invalid_section(tmp_path):
    # The invalid section will be removed from the file
    data = "non_existing_section:\n   foo: bar"

    fake_path = tmp_path / 'fake_path.yml'
    fake_path.write_text(data)

    settings = NapariSettings(fake_path)
    assert getattr(settings, "non_existing_section", None) is None
Example #9
0
def test_settings_only_saves_non_default_values(monkeypatch, tmp_path):
    from yaml import safe_load

    # prevent error during NAPARI_ASYNC tests
    monkeypatch.setattr(os, 'environ', {})

    # manually get all default data and write to yaml file
    all_data = NapariSettings(None).yaml()
    fake_path = tmp_path / 'fake_path.yml'
    assert 'appearance' in all_data
    assert 'application' in all_data
    fake_path.write_text(all_data)

    # load that yaml file and resave
    NapariSettings(fake_path).save()

    # make sure that it's now just an empty dict
    assert not safe_load(fake_path.read_text())
Example #10
0
def test_migration_saves(_test_migrator):
    @_test_migrator('0.1.0', '0.2.0')
    def _(model: NapariSettings):
        ...

    with patch.object(NapariSettings, 'save') as mock:
        mock.assert_not_called()
        settings = NapariSettings(config_path='junk', schema_version='0.1.0')
        assert settings.schema_version == '0.2.0'
        mock.assert_called()
Example #11
0
def test_settings_only_saves_non_default_values(monkeypatch, tmp_path):
    from yaml import safe_load

    # prevent error during NAPARI_ASYNC tests
    monkeypatch.setattr(os, 'environ', {})

    # manually get all default data and write to yaml file
    all_data = NapariSettings(None).yaml()
    fake_path = tmp_path / 'fake_path.yml'
    assert 'appearance' in all_data
    assert 'application' in all_data
    fake_path.write_text(all_data)

    # load that yaml file and resave
    NapariSettings(fake_path).save()

    # make sure that the only value is now the schema version
    assert safe_load(fake_path.read_text()) == {
        'schema_version': CURRENT_SCHEMA_VERSION
    }
Example #12
0
def test_migration_works(_test_migrator):
    # test that a basic migrator works to change the version
    # and mutate the model

    @_test_migrator('0.1.0', '0.2.0')
    def _(model: NapariSettings):
        model.appearance.theme = 'light'

    settings = NapariSettings(schema_version='0.1.0')
    assert settings.schema_version == '0.2.0'
    assert settings.appearance.theme == 'light'
Example #13
0
def test_040_to_050_migration():
    # Prior to 0.5.0 existing preferences may have reader extensions
    # preferences saved without a leading *.
    # fnmatch would fail on these so we coerce them to include a *
    # e.g. '.csv' becomes '*.csv'
    settings = NapariSettings(
        schema_version='0.4.0',
        plugins={'extension2reader': {
            '.tif': 'napari'
        }},
    )
    assert '.tif' not in settings.plugins.extension2reader
    assert '*.tif' in settings.plugins.extension2reader
Example #14
0
def test_failed_migration_leaves_version(_test_migrator):
    # if an error occurs IN the migrator, the version should stay
    # where it was before the migration, and any changes reverted.
    @_test_migrator('0.1.0', '0.2.0')
    def _(model: NapariSettings):
        model.appearance.theme = 'light'
        assert model.appearance.theme == 'light'
        raise ValueError('broken migration')

    with pytest.warns(UserWarning) as e:
        settings = NapariSettings(schema_version='0.1.0')
    assert settings.schema_version == '0.1.0'
    # test migration was atomic, and reverted the theme change
    assert settings.appearance.theme == 'dark'
    # test that the user was warned
    assert 'Failed to migrate settings from v0.1.0 to v0.2.0' in str(e[0])
Example #15
0
def test_030_to_040_migration():
    # Prior to v0.4.0, npe2 plugins were automatically "disabled"
    # 0.3.0 -> 0.4.0 should remove any installed npe2 plugins from the
    # set of disabled plugins (see migrator for details)
    try:
        d = distribution('napari-svg')
        assert 'napari.manifest' in {ep.group for ep in d.entry_points}
    except Exception:
        pytest.fail('napari-svg not present as an npe2 plugin. '
                    'This test needs updating')

    settings = NapariSettings(
        schema_version='0.3.0',
        plugins={'disabled_plugins': {'napari-svg', 'napari'}},
    )
    assert 'napari-svg' not in settings.plugins.disabled_plugins
    assert 'napari' not in settings.plugins.disabled_plugins
Example #16
0
def test_settings_env_variables(monkeypatch):
    assert NapariSettings(None).appearance.theme == 'dark'
    # NOTE: this was previously tested as NAPARI_THEME
    monkeypatch.setenv('NAPARI_APPEARANCE_THEME', 'light')
    assert NapariSettings(None).appearance.theme == 'light'

    # can also use json
    assert NapariSettings(None).application.first_time is True
    # NOTE: this was previously tested as NAPARI_THEME
    monkeypatch.setenv('NAPARI_APPLICATION', '{"first_time": "false"}')
    assert NapariSettings(None).application.first_time is False

    # can also use json in nested vars
    assert NapariSettings(None).plugins.extension2reader == {}
    monkeypatch.setenv('NAPARI_PLUGINS_EXTENSION2READER', '{"*.zarr": "hi"}')
    assert NapariSettings(None).plugins.extension2reader == {"*.zarr": "hi"}
Example #17
0
 def _mock_save(self, path=None, **dict_kwargs):
     if not (path or self.config_path):
         return
     NapariSettings.__original_save__(self, path, **dict_kwargs)
Example #18
0
def test_settings_env_variables_fails(monkeypatch):
    monkeypatch.setenv('NAPARI_APPEARANCE_THEME', 'FOOBAR')
    with pytest.raises(pydantic.ValidationError):
        NapariSettings()
Example #19
0
def test_settings_load_invalid_content(tmp_path):
    # This is invalid content

    fake_path = tmp_path / 'fake_path.yml'
    fake_path.write_text(":")
    NapariSettings(fake_path)
Example #20
0
def test_settings_loads(tmp_path):
    data = "appearance:\n   theme: light"
    fake_path = tmp_path / 'fake_path.yml'
    fake_path.write_text(data)
    assert NapariSettings(fake_path).appearance.theme == "light"
Example #21
0
def test_full_serialize(test_settings: NapariSettings, tmp_path, ext):
    """Make sure that every object in the settings is serializeable.

    Should work with both json and yaml.
    """
    test_settings.save(tmp_path / f't.{ext}', exclude_defaults=False)
Example #22
0
def test_no_migrations_available(_test_migrator):
    # no migrators exist... nothing should happen
    settings = NapariSettings(schema_version='0.1.0')
    assert settings.schema_version == '0.1.0'
Example #23
0
def test_first_time():
    """This test just confirms that we don't load an existing file (locally)"""
    assert NapariSettings().application.first_time is True