diff options
| author | Fabian Freund <mail@fabi.online> | 2026-04-28 23:42:29 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-28 17:42:29 +0200 |
| commit | ed5955a5c7ff3dc5cfca4fcdd57d2eef4564049b (patch) | |
| tree | aa41ec80fb7f882e8c74c7e269d21d7a0d54efe7 /searx/result_types | |
| parent | a7ac696b4a146af905397b8b9a07b18f4cd42bb5 (diff) | |
[fix] Result.defaults_from() inverted logic (#6019)
The bug was introduced in commit 8769b7c6d (typification of result items); this
patch fixes the bug and also addresses the peculiarity that fields can be set
but contain no *usable* value:
If a field is set (exists) but contains an empty string or the value ``None``,
it is also considered *not set*. This also ensures that an integer 0 is
evaluated *as set*!
Co-Authored: Markus Heiser <markus.heiser@darmarit.de>
Diffstat (limited to 'searx/result_types')
| -rw-r--r-- | searx/result_types/_base.py | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/searx/result_types/_base.py b/searx/result_types/_base.py index 04e95dc07..e83be4382 100644 --- a/searx/result_types/_base.py +++ b/searx/result_types/_base.py @@ -32,7 +32,7 @@ import msgspec from searx import logger as log WHITESPACE_REGEX = re.compile('( |\t|\n)+', re.M | re.U) -UNKNOWN = object() +UNSET = object() def _normalize_url_fields(result: "Result | LegacyResult"): @@ -326,12 +326,13 @@ class Result(msgspec.Struct, kw_only=True): def defaults_from(self, other: "Result"): """Fields not set in *self* will be updated from the field values of the - *other*. + *other*. If a field is set (exists) but contains an empty string + or the value ``None``, it is also considered *not set*. """ for field_name in self.__struct_fields__: - self_val = getattr(self, field_name, False) - other_val = getattr(other, field_name, False) - if self_val: + self_val = getattr(self, field_name, UNSET) + other_val = getattr(other, field_name, UNSET) + if self_val is UNSET and other_val not in (UNSET, "", None): setattr(self, field_name, other_val) @@ -440,8 +441,6 @@ class LegacyResult(dict[str, t.Any]): Do not use this class in your own implementations! """ - UNSET: object = object() - # emulate field types from type class Result url: str | None template: str @@ -512,7 +511,7 @@ class LegacyResult(dict[str, t.Any]): ) def __getattr__(self, name: str, default: t.Any = UNSET) -> t.Any: - if default == self.UNSET and name not in self: + if default == UNSET and name not in self: raise AttributeError(f"LegacyResult object has no field named: {name}") return self[name] @@ -563,9 +562,12 @@ class LegacyResult(dict[str, t.Any]): self.engines.add(self.engine) def defaults_from(self, other: "LegacyResult"): - for k, v in other.items(): - if not self.get(k): - self[k] = v + # If a field is set (exists) but contains an empty string or the value + # ``None``, it is also considered *not set*. + for field_name, other_val in other.items(): + self_val = self.get(field_name, UNSET) + if self_val is UNSET and other_val not in ("", UNSET): + self[field_name] = other_val def filter_urls(self, filter_func: "Callable[[Result | LegacyResult, str, str], str | bool]"): """See :py:obj:`Result.filter_urls`""" |
