Source code for galaxy.forms.forms
"""
FormDefinition and field factories
"""
# TODO: A FormDefinitionField is closely linked to a form_builder result.
# Can this functionality be further abstracted and merged with form_builder?
from galaxy.model import (
FormDefinition,
FormDefinitionCurrent,
)
from galaxy.util import string_as_bool
FORM_TYPES = {f_type.lower(): f_descript for f_type, f_descript in FormDefinition.types.__members__.items()}
[docs]class FormDefinitionFactory:
[docs] def __init__(self, form_types, field_type_factories):
self.form_types = form_types
self.field_type_factories = field_type_factories
[docs] def new(self, form_type, name, description=None, fields=None, layout=None, form_definition_current=None):
"""
Return new FormDefinition.
"""
assert (
form_type in self.form_types
), f"Invalid FormDefinition type ( {form_type} not in {self.form_types.keys()} )"
assert name, "FormDefinition requires a name"
if description is None:
description = ""
if layout is None:
layout = []
if fields is None:
fields = []
# Create new FormDefinitionCurrent
if form_definition_current is None:
form_definition_current = FormDefinitionCurrent()
rval = FormDefinition(
name=name,
desc=description,
form_type=self.form_types[form_type],
form_definition_current=form_definition_current,
layout=layout,
fields=fields,
)
form_definition_current.latest_form = rval
return rval
[docs] def from_elem(self, elem, form_definition_current=None):
"""
Return FormDefinition created from an xml element.
"""
name = elem.get("name", None)
description = elem.get("description", None)
form_type = elem.get("type", None)
# load layout
layout = []
if layouts_elem := elem.find("layout"):
for layout_elem in layouts_elem.findall("grid"):
layout_name = layout_elem.get("name", None)
assert layout_name and layout_name not in layout, "Layout grid element requires a unique name."
layout.append(layout_name)
# load fields
fields = []
if (fields_elem := elem.find("fields")) is not None:
for field_elem in fields_elem.findall("field"):
field_type = field_elem.get("type")
assert field_type in self.field_type_factories, f"Invalid form field type ( {field_type} )."
fields.append(self.field_type_factories[field_type].from_elem(field_elem, layout))
# create and return new form
return self.new(
form_type,
name,
description=description,
fields=fields,
layout=layout,
form_definition_current=form_definition_current,
)
[docs]class FormDefinitionFieldFactory:
type: str
def __get_stored_field_type(self, **kwds):
raise Exception("not implemented")
[docs] def new(self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None):
"""
Return new FormDefinition field.
"""
rval = {}
assert name, "Must provide a name"
rval["name"] = name
if not label:
rval["label"] = name
else:
rval["label"] = label
if required:
rval["required"] = "required"
else:
rval["required"] = "optional"
if helptext is None:
helptext = ""
rval["helptext"] = helptext
if default is None:
default = ""
rval["default"] = default
rval["visible"] = visible
# if layout is None: #is this needed?
# layout = ''
rval["layout"] = layout
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition created from an xml element.
"""
name = elem.get("name")
label = elem.get("label")
required = string_as_bool(elem.get("required", "false"))
default = elem.get("value")
helptext = elem.get("helptext")
visible = string_as_bool(elem.get("visible", "true"))
field_layout = elem.get("layout", None)
if field_layout:
assert layout and field_layout in layout, f"Invalid layout specified: {field_layout} not in {layout}"
field_layout = str(
layout.index(field_layout)
) # existing behavior: integer indexes are stored as strings. why?
return self.new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=field_layout,
)
[docs]class FormDefinitionTextFieldFactory(FormDefinitionFieldFactory):
type = "text"
def __get_stored_field_type(self, area):
if area:
return "TextArea"
else:
return "TextField"
[docs] def new(
self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None, area=False
):
"""
Return new FormDefinition field.
"""
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type(area)
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type(string_as_bool(elem.get("area", "false")))
return rval
[docs]class FormDefinitionPasswordFieldFactory(FormDefinitionFieldFactory):
type = "password"
def __get_stored_field_type(self):
return "PasswordField"
[docs] def new(
self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None, area=False
):
"""
Return new FormDefinition field.
"""
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type()
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type()
return rval
[docs]class FormDefinitionAddressFieldFactory(FormDefinitionFieldFactory):
type = "address"
def __get_stored_field_type(self):
return "AddressField"
[docs] def new(self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None):
"""
Return new FormDefinition field.
"""
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type()
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type()
return rval
[docs]class FormDefinitionWorkflowFieldFactory(FormDefinitionFieldFactory):
type = "workflow"
def __get_stored_field_type(self):
return "WorkflowField"
[docs] def new(self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None):
"""
Return new FormDefinition field.
"""
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type()
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type()
return rval
[docs]class FormDefinitionWorkflowMappingFieldFactory(FormDefinitionFieldFactory):
type = "workflowmapping"
def __get_stored_field_type(self):
return "WorkflowMappingField"
[docs] def new(self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None):
"""
Return new FormDefinition field.
"""
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type()
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type()
return rval
[docs]class FormDefinitionHistoryFieldFactory(FormDefinitionFieldFactory):
type = "history"
def __get_stored_field_type(self):
return "HistoryField"
[docs] def new(self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None):
"""
Return new FormDefinition field.
"""
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type()
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type()
return rval
[docs]class FormDefinitionSelectFieldFactory(FormDefinitionFieldFactory):
type = "select"
def __get_stored_field_type(self, checkboxes):
if checkboxes:
return "CheckboxField"
else:
return "SelectField"
[docs] def new(
self,
name=None,
label=None,
required=False,
helptext=None,
default=None,
visible=True,
layout=None,
options=None,
checkboxes=False,
):
"""
Return new FormDefinition field.
"""
options = options or []
rval = super().new(
name=name,
label=label,
required=required,
helptext=helptext,
default=default,
visible=visible,
layout=layout,
)
rval["type"] = self.__get_stored_field_type(checkboxes)
if options is None:
options = []
rval["selectlist"] = options
return rval
[docs] def from_elem(self, elem, layout=None):
"""
Return FormDefinition field created from an xml element.
"""
rval = super().from_elem(elem, layout=layout)
rval["type"] = self.__get_stored_field_type(string_as_bool(elem.get("checkboxes", "false")))
# load select options
rval["selectlist"] = []
for select_option in elem.findall("option"):
value = select_option.get("value", None)
assert value is not None, 'Must provide a "value" for a select option'
rval["selectlist"].append(value)
return rval
field_type_factories = {
field.type: field()
for field in (
FormDefinitionTextFieldFactory,
FormDefinitionPasswordFieldFactory,
FormDefinitionAddressFieldFactory,
FormDefinitionSelectFieldFactory,
FormDefinitionWorkflowFieldFactory,
FormDefinitionWorkflowMappingFieldFactory,
FormDefinitionHistoryFieldFactory,
)
}
form_factory = FormDefinitionFactory(FORM_TYPES, field_type_factories)