From cb5895c1d3ec747d589cd00d25fa924154763947 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Tue, 9 Nov 2021 09:52:38 +0100 Subject: [PATCH 1/2] formdef: make get_data raise on error if necessary (#56824) --- wcs/data_sources.py | 12 +++++++++--- wcs/fields.py | 35 ++++++++++++++++++++++++++--------- wcs/formdef.py | 8 ++++---- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/wcs/data_sources.py b/wcs/data_sources.py index bcdcf9f5..8b6e2cb0 100644 --- a/wcs/data_sources.py +++ b/wcs/data_sources.py @@ -40,6 +40,10 @@ from .qommon.xml_storage import XmlStorableObject data_source_functions = {} +class DataSourceError(Exception): + pass + + def register_data_source_function(function, function_name=None): if not function_name: function_name = function.__name__ @@ -264,14 +268,14 @@ def request_geojson_items(url, data_source): return items -def get_structured_items(data_source, mode=None, include_disabled=True): - items = _get_structured_items(data_source, mode=mode) +def get_structured_items(data_source, mode=None, include_disabled=True, raise_on_error=False): + items = _get_structured_items(data_source, mode=mode, raise_on_error=raise_on_error) if not include_disabled: items = [i for i in items if not i.get('disabled')] return items -def _get_structured_items(data_source, mode=None): +def _get_structured_items(data_source, mode=None, raise_on_error=False): cache_duration = 0 if data_source.get('type') and data_source.get('type').startswith('carddef:'): @@ -379,6 +383,8 @@ def _get_structured_items(data_source, mode=None): else: items = request_json_items(url, data_source) if items is None: + if raise_on_error: + raise DataSourceError('datasource %s is unavailable' % url) return [] if hasattr(request, 'datasources_cache'): request.datasources_cache[url] = items diff --git a/wcs/fields.py b/wcs/fields.py index f940a2d9..4a47b603 100644 --- a/wcs/fields.py +++ b/wcs/fields.py @@ -87,6 +87,10 @@ from .qommon.upload_storage import PicklableUpload from .sessions import BasicSession +class SetValueError(Exception): + pass + + class PrefillSelectionWidget(CompositeWidget): def __init__(self, name, value=None, field=None, **kwargs): CompositeWidget.__init__(self, name, value, **kwargs) @@ -618,16 +622,18 @@ class Field: return value return str(value) - def set_value(self, data, value): + def set_value(self, data, value, raise_on_error=False): data['%s' % self.id] = value if self.store_display_value: display_value = self.store_display_value(data, self.id) + if raise_on_error and display_value is None: + raise SetValueError('a datasource is unavailable') if display_value: data['%s_display' % self.id] = display_value elif '%s_display' % self.id in data: del data['%s_display' % self.id] if self.store_structured_value and value: - structured_value = self.store_structured_value(data, self.id) + structured_value = self.store_structured_value(data, self.id, raise_on_error=raise_on_error) if structured_value: if isinstance(structured_value, dict) and structured_value.get('id'): # in case of list field, override id @@ -2053,7 +2059,7 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin): else: widget.extra_css_class = self.extra_css_class - def store_display_value(self, data, field_id): + def store_display_value(self, data, field_id, raise_on_error=False): value = data.get(field_id) if not value: return '' @@ -2077,7 +2083,7 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin): return display_value return self.get_display_value(value) - def store_structured_value(self, data, field_id): + def store_structured_value(self, data, field_id, raise_on_error=False): data_source = data_sources.get_object(self.data_source) if data_source is None: return @@ -2086,6 +2092,9 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin): return value = data_source.get_structured_value(data.get(field_id)) + if value is None and raise_on_error: + raise SetValueError('a datasource is unavailable') + if value is None or set(value.keys()) == {'id', 'text'}: return return value @@ -2409,7 +2418,7 @@ class ItemsField(WidgetField, ItemFieldMixin): values.extend([''] * (nb_columns - len(values))) return values - def store_display_value(self, data, field_id): + def store_display_value(self, data, field_id, raise_on_error=False): options = self.get_options() if not options: return '' @@ -2428,12 +2437,20 @@ class ItemsField(WidgetField, ItemFieldMixin): if str(key) == str(choice): choices.append(option_value) break + else: + if raise_on_error: + raise SetValueError('datasource is unavailable') return ', '.join(choices) - def store_structured_value(self, data, field_id): + def store_structured_value(self, data, field_id, raise_on_error=False): if not self.data_source: return - structured_options = data_sources.get_structured_items(self.data_source) + try: + structured_options = data_sources.get_structured_items( + self.data_source, raise_on_error=raise_on_error + ) + except data_sources.DataSourceError as e: + raise SetValueError(str(e)) if not structured_options: return structured_value = [] @@ -3120,7 +3137,7 @@ class MapField(WidgetField, MapOptionsMixin): def get_structured_value(self, data): return self.get_json_value(data.get(self.id)) - def set_value(self, data, value): + def set_value(self, data, value, raise_on_error=False): if value and ';' not in value: raise Exception('invalid coordinates %r (missing ;)' % value) super().set_value(data, value) @@ -3372,7 +3389,7 @@ class BlockField(WidgetField): 'remove_button', ] - def store_display_value(self, data, field_id): + def store_display_value(self, data, field_id, raise_on_error=False): value = data.get(field_id) parts = [] if value and value.get('data'): diff --git a/wcs/formdef.py b/wcs/formdef.py index a9cf013a..5a28df71 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -822,22 +822,22 @@ class FormDef(StorableObject): widget.live_condition_fields = live_condition_fields[field.varname] @classmethod - def get_field_data(cls, field, widget): + def get_field_data(cls, field, widget, raise_on_error=False): d = {} d[field.id] = widget.parse() if d.get(field.id) is not None and field.convert_value_from_str: d[field.id] = field.convert_value_from_str(d[field.id]) - field.set_value(d, d[field.id]) + field.set_value(d, d[field.id], raise_on_error=raise_on_error) if getattr(widget, 'cleanup', None): widget.cleanup() return d - def get_data(self, form): + def get_data(self, form, raise_on_error=False): d = {} for field in self.fields: widget = form.get_widget('f%s' % field.id) if widget: - d.update(self.get_field_data(field, widget)) + d.update(self.get_field_data(field, widget, raise_on_error=raise_on_error)) return d def export_to_json(self, include_id=False, indent=None): -- 2.33.0