From c29463bfd684450eb721ab1b131d47b8fc002b9c Mon Sep 17 00:00:00 2001 From: Tim Sweeney Date: Fri, 15 Jan 2021 07:06:22 -0800 Subject: [PATCH] [WB-4221] CLI now has ability to preprocess settings and uses this to strip slashes from URL (#1692) * Added preprocess behavior --- tests/wandb_settings_test.py | 12 ++++++++ wandb/sdk/wandb_settings.py | 47 +++++++++++++++++++++----------- wandb/sdk_py27/wandb_settings.py | 47 +++++++++++++++++++++----------- 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/tests/wandb_settings_test.py b/tests/wandb_settings_test.py index 157c1f3e28e..18d3974326b 100644 --- a/tests/wandb_settings_test.py +++ b/tests/wandb_settings_test.py @@ -224,3 +224,15 @@ def test_prio_context_over_ignore(): with s._as_source(s.Source.PROJECT, override=True) as s2: s2.project = "pizza2" assert s.project == "pizza" + + +def test_preprocess_base_url(): + s = Settings() + s.update(base_url="http://host.com") + assert s.base_url == "http://host.com" + s.update(base_url="http://host.com/") + assert s.base_url == "http://host.com" + s.update(base_url="http://host.com///") + assert s.base_url == "http://host.com" + s.update(base_url="//http://host.com//") + assert s.base_url == "//http://host.com" diff --git a/wandb/sdk/wandb_settings.py b/wandb/sdk/wandb_settings.py index 2273dc0e597..203c7c04b6b 100644 --- a/wandb/sdk/wandb_settings.py +++ b/wandb/sdk/wandb_settings.py @@ -560,6 +560,11 @@ def _validate_show_errors(self, value): if val is None: return "{} is not a boolean".format(value) + def _preprocess_base_url(self, value): + if value is not None: + value = value.rstrip("/") + return value + def _start_run(self): datetime_now: datetime = datetime.now() time_now: float = time.time() @@ -676,30 +681,39 @@ def _check_invalid(self, k, v): if invalid: raise TypeError("Settings field {}: {}".format(k, invalid)) + def _perform_preprocess(self, k, v): + f = getattr(self, "_preprocess_" + k, None) + if not f or not callable(f): + return v + else: + return f(v) + def _update(self, __d=None, _source=None, _override=None, **kwargs): if self.__frozen and (__d or kwargs): raise TypeError("Settings object is frozen") d = __d or dict() + data = {} for check in d, kwargs: for k in six.viewkeys(check): if k not in self.__dict__: raise KeyError(k) - self._check_invalid(k, check[k]) - for data in d, kwargs: - for k, v in six.iteritems(data): - if v is None: - continue - if self._priority_failed(k, source=_source, override=_override): - continue - if isinstance(v, list): - v = tuple(v) - self.__dict__[k] = v - if _source: - self.__defaults_dict[k] = _source - self.__defaults_dict_set.setdefault(k, set()).add(_source) - if _override: - self.__override_dict[k] = _override - self.__override_dict_set.setdefault(k, set()).add(_override) + v = self._perform_preprocess(k, check[k]) + self._check_invalid(k, v) + data[k] = v + for k, v in six.iteritems(data): + if v is None: + continue + if self._priority_failed(k, source=_source, override=_override): + continue + if isinstance(v, list): + v = tuple(v) + self.__dict__[k] = v + if _source: + self.__defaults_dict[k] = _source + self.__defaults_dict_set.setdefault(k, set()).add(_source) + if _override: + self.__override_dict[k] = _override + self.__override_dict_set.setdefault(k, set()).add(_override) def update(self, __d=None, **kwargs): self._update(__d, **kwargs) @@ -812,6 +826,7 @@ def __setattr__(self, name, value): raise AttributeError(name) if self.__frozen: raise TypeError("Settings object is frozen") + value = self._perform_preprocess(name, value) self._check_invalid(name, value) object.__setattr__(self, name, value) diff --git a/wandb/sdk_py27/wandb_settings.py b/wandb/sdk_py27/wandb_settings.py index aeaa63b562f..4638cb8e5ad 100644 --- a/wandb/sdk_py27/wandb_settings.py +++ b/wandb/sdk_py27/wandb_settings.py @@ -560,6 +560,11 @@ def _validate_show_errors(self, value): if val is None: return "{} is not a boolean".format(value) + def _preprocess_base_url(self, value): + if value is not None: + value = value.rstrip("/") + return value + def _start_run(self): datetime_now = datetime.now() time_now = time.time() @@ -676,30 +681,39 @@ def _check_invalid(self, k, v): if invalid: raise TypeError("Settings field {}: {}".format(k, invalid)) + def _perform_preprocess(self, k, v): + f = getattr(self, "_preprocess_" + k, None) + if not f or not callable(f): + return v + else: + return f(v) + def _update(self, __d=None, _source=None, _override=None, **kwargs): if self.__frozen and (__d or kwargs): raise TypeError("Settings object is frozen") d = __d or dict() + data = {} for check in d, kwargs: for k in six.viewkeys(check): if k not in self.__dict__: raise KeyError(k) - self._check_invalid(k, check[k]) - for data in d, kwargs: - for k, v in six.iteritems(data): - if v is None: - continue - if self._priority_failed(k, source=_source, override=_override): - continue - if isinstance(v, list): - v = tuple(v) - self.__dict__[k] = v - if _source: - self.__defaults_dict[k] = _source - self.__defaults_dict_set.setdefault(k, set()).add(_source) - if _override: - self.__override_dict[k] = _override - self.__override_dict_set.setdefault(k, set()).add(_override) + v = self._perform_preprocess(k, check[k]) + self._check_invalid(k, v) + data[k] = v + for k, v in six.iteritems(data): + if v is None: + continue + if self._priority_failed(k, source=_source, override=_override): + continue + if isinstance(v, list): + v = tuple(v) + self.__dict__[k] = v + if _source: + self.__defaults_dict[k] = _source + self.__defaults_dict_set.setdefault(k, set()).add(_source) + if _override: + self.__override_dict[k] = _override + self.__override_dict_set.setdefault(k, set()).add(_override) def update(self, __d=None, **kwargs): self._update(__d, **kwargs) @@ -812,6 +826,7 @@ def __setattr__(self, name, value): raise AttributeError(name) if self.__frozen: raise TypeError("Settings object is frozen") + value = self._perform_preprocess(name, value) self._check_invalid(name, value) object.__setattr__(self, name, value)