# Buggy code
def _workflow_to_dict_editor(self, trans, stored):
    """ """
    workflow = stored.latest_workflow
    # Pack workflow data into a dictionary and return
    data = {}
    data["name"] = workflow.name
    data["steps"] = {}
    data["upgrade_messages"] = {}
    # For each step, rebuild the form and encode the state
    for step in workflow.steps:
        # Load from database representation
        module = module_factory.from_workflow_step(trans, step)
        if not module:
            step_annotation = self.get_item_annotation_obj(
                trans.sa_session, trans.user, step
            )
            annotation_str = ""
            if step_annotation:
                annotation_str = step_annotation.annotation
            invalid_tool_form_html = """<div class="toolForm tool-node-error">
                                            <div class="toolFormTitle form-row-error">Unrecognized Tool: %s</div>
                                            <div class="toolFormBody"><div class="form-row">
                                            The tool id '%s' for this tool is unrecognized.<br/><br/>
                                            To save this workflow, you will need to delete this step or enable the tool.
                                            </div></div></div>""" % (
                step.tool_id,
                step.tool_id,
            )
            step_dict = {
                "id": step.order_index,
                "type": "invalid",
                "tool_id": step.tool_id,
                "name": "Unrecognized Tool: %s" % step.tool_id,
                "tool_state": None,
                "tooltip": None,
                "tool_errors": ["Unrecognized Tool Id: %s" % step.tool_id],
                "data_inputs": [],
                "data_outputs": [],
                "form_html": invalid_tool_form_html,
                "annotation": annotation_str,
                "input_connections": {},
                "post_job_actions": {},
                "uuid": str(step.uuid),
                "label": step.label or None,
                "workflow_outputs": [],
            }
            # Position
            step_dict["position"] = step.position
            # Add to return value
            data["steps"][step.order_index] = step_dict
            continue
        # Fix any missing parameters
        upgrade_message = module.check_and_update_state()
        if upgrade_message:
            # FIXME: Frontend should be able to handle workflow messages
            #        as a dictionary not just the values
            data["upgrade_messages"][step.order_index] = upgrade_message.values()
        # Get user annotation.
        step_annotation = self.get_item_annotation_obj(
            trans.sa_session, trans.user, step
        )
        annotation_str = ""
        if step_annotation:
            annotation_str = step_annotation.annotation
        # Pack attributes into plain dictionary
        step_dict = {
            "id": step.order_index,
            "type": module.type,
            "tool_id": module.get_tool_id(),
            "name": module.get_name(),
            "tool_state": module.get_state(),
            "tooltip": module.get_tooltip(static_path=url_for("/static")),
            "tool_errors": module.get_errors(),
            "data_inputs": module.get_data_inputs(),
            "data_outputs": module.get_data_outputs(),
            "form_html": module.get_config_form(),
            "annotation": annotation_str,
            "post_job_actions": {},
            "uuid": str(step.uuid) if step.uuid else None,
            "label": step.label or None,
            "workflow_outputs": [],
        }
        # Connections
        input_connections = step.input_connections
        input_connections_type = {}
        multiple_input = {}  # Boolean value indicating if this can be mutliple
        if step.type is None or step.type == "tool":
            # Determine full (prefixed) names of valid input datasets
            data_input_names = {}

            def callback(input, value, prefixed_name, prefixed_label):
                if isinstance(input, DataToolParameter) or isinstance(
                    input, DataCollectionToolParameter
                ):
                    data_input_names[prefixed_name] = True
                    multiple_input[prefixed_name] = input.multiple
                    if isinstance(input, DataToolParameter):
                        input_connections_type[input.name] = "dataset"
                    if isinstance(input, DataCollectionToolParameter):
                        input_connections_type[input.name] = "dataset_collection"

            visit_input_values(module.tool.inputs, module.state.inputs, callback)
            # Filter
            # FIXME: this removes connection without displaying a message currently!
            input_connections = [
                conn
                for conn in input_connections
                if conn.input_name in data_input_names
            ]
            # post_job_actions
            pja_dict = {}
            for pja in step.post_job_actions:
                pja_dict[pja.action_type + pja.output_name] = dict(
                    action_type=pja.action_type,
                    output_name=pja.output_name,
                    action_arguments=pja.action_arguments,
                )
            step_dict["post_job_actions"] = pja_dict
            # workflow outputs
            outputs = []
            for output in step.workflow_outputs:
                outputs.append(output.output_name)
            step_dict["workflow_outputs"] = outputs
        # Encode input connections as dictionary
        input_conn_dict = {}
        for conn in input_connections:
            input_type = "dataset"
            if conn.input_name in input_connections_type:
                input_type = input_connections_type[conn.input_name]
            conn_dict = dict(
                id=conn.output_step.order_index,
                output_name=conn.output_name,
                input_type=input_type,
            )
            if conn.input_name in multiple_input:
                if conn.input_name in input_conn_dict:
                    input_conn_dict[conn.input_name].append(conn_dict)
                else:
                    input_conn_dict[conn.input_name] = [conn_dict]
            else:
                input_conn_dict[conn.input_name] = conn_dict
        step_dict["input_connections"] = input_conn_dict
        # Position
        step_dict["position"] = step.position
        # Add to return value
        data["steps"][step.order_index] = step_dict
    return data


# Traceback (AssertionError)
======================================================================
FAIL: test_export_editor (api.test_workflows.WorkflowsApiTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/opt/galaxy/test/api/test_workflows.py", line 395, in test_export_editor
downloaded_workflow = self._download_workflow( uploaded_workflow_id, style="editor" )
File "/opt/galaxy/test/api/test_workflows.py", line 1155, in _download_workflow
self._assert_status_code_is( download_response, 200 )
File "/opt/galaxy/test/base/api.py", line 82, in _assert_status_code_is
assert_status_code_is( response, expected_status_code )
File "/opt/galaxy/test/base/api_asserts.py", line 15, in assert_status_code_is
raise AssertionError( assertion_message )
AssertionError: Request status code (500) was not expected value 200. Body was {u'err_msg': u'Uncaught exception in exposed API method:', u'err_code': 0}
-------------------- >> begin captured logging << --------------------
requests.packages.urllib3.connectionpool: INFO: Starting new HTTP connection (1): localhost
galaxy.web.framework.webapp: INFO: Session authenticated using Galaxy master api key
requests.packages.urllib3.connectionpool: DEBUG: "GET /api/users?key=TEST123 HTTP/1.1" 200 None
requests.packages.urllib3.connectionpool: INFO: Starting new HTTP connection (1): localhost
galaxy.web.framework.webapp: INFO: Session authenticated using Galaxy master api key
requests.packages.urllib3.connectionpool: DEBUG: "POST /api/users/adb5f5c93f827949/api_key HTTP/1.1" 200 None
requests.packages.urllib3.connectionpool: INFO: Starting new HTTP connection (1): localhost
requests.packages.urllib3.connectionpool: DEBUG: "POST /api/workflows/upload HTTP/1.1" 200 None
requests.packages.urllib3.connectionpool: INFO: Starting new HTTP connection (1): localhost
galaxy.tools: ERROR: tools::to_json - [history_id=None] Failed to retrieve history. History unavailable. Please specify a valid history id..
Traceback (most recent call last):
File "/opt/galaxy/lib/galaxy/tools/__init__.py", line 2347, in to_json
raise Exception('History unavailable. Please specify a valid history id')
Exception: History unavailable. Please specify a valid history id
galaxy.web.framework.decorators: ERROR: Uncaught exception in exposed API method:
Traceback (most recent call last):
File "/opt/galaxy/lib/galaxy/web/framework/decorators.py", line 260, in decorator
rval = func( self, trans, *args, **kwargs)
File "/opt/galaxy/lib/galaxy/webapps/galaxy/api/workflows.py", line 232, in workflow_dict
ret_dict = self.workflow_contents_manager.workflow_to_dict( trans, stored_workflow, style=style )
File "/opt/galaxy/lib/galaxy/managers/workflows.py", line 274, in workflow_to_dict
return self._workflow_to_dict_editor( trans, stored )
File "/opt/galaxy/lib/galaxy/managers/workflows.py", line 349, in _workflow_to_dict_editor
'form_html': module.get_config_form(),
File "/opt/galaxy/lib/galaxy/workflow/modules.py", line 717, in get_config_form
tool=self.tool, values=self.state.inputs, errors=( self.errors or {} ) )
File "/opt/galaxy/lib/galaxy/web/framework/webapp.py", line 809, in fill_template
return self.fill_template_mako( filename, **kwargs )
File "/opt/galaxy/lib/galaxy/web/framework/webapp.py", line 823, in fill_template_mako
return template.render( **data )
File "/opt/galaxy/eggs/Mako-0.4.1-py2.7.egg/mako/template.py", line 296, in render
return runtime._render(self, self.callable_, args, data)
File "/opt/galaxy/eggs/Mako-0.4.1-py2.7.egg/mako/runtime.py", line 660, in _render
**_kwargs_for_callable(callable_, data))
File "/opt/galaxy/eggs/Mako-0.4.1-py2.7.egg/mako/runtime.py", line 692, in _render_context
_exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
File "/opt/galaxy/eggs/Mako-0.4.1-py2.7.egg/mako/runtime.py", line 718, in _exec_template
callable_(context, *args, **kwargs)
File "/opt/galaxy/database/compiled_templates/workflow/editor_tool_form.mako.py", line 37, in render_body
'history_id'        : trans.security.encode_id( trans.history.id ),
AttributeError: 'NoneType' object has no attribute 'id'
requests.packages.urllib3.connectionpool: DEBUG: "GET /api/workflows/917af94b51aeccc8/download?style=editor&amp;key=08b6c93ec530f27b033916ff5a7dbf70 HTTP/1.1" 500 None
--------------------- >> end captured logging << ---------------------

# Fixed code
def _workflow_to_dict_editor(self, trans, stored):
    """ """
    workflow = stored.latest_workflow
    # Pack workflow data into a dictionary and return
    data = {}
    data["name"] = workflow.name
    data["steps"] = {}
    data["upgrade_messages"] = {}
    # For each step, rebuild the form and encode the state
    for step in workflow.steps:
        # Load from database representation
        module = module_factory.from_workflow_step(trans, step)
        if not module:
            step_annotation = self.get_item_annotation_obj(
                trans.sa_session, trans.user, step
            )
            annotation_str = ""
            if step_annotation:
                annotation_str = step_annotation.annotation
            invalid_tool_form_html = """<div class="toolForm tool-node-error">
                                            <div class="toolFormTitle form-row-error">Unrecognized Tool: %s</div>
                                            <div class="toolFormBody"><div class="form-row">
                                            The tool id '%s' for this tool is unrecognized.<br/><br/>
                                            To save this workflow, you will need to delete this step or enable the tool.
                                            </div></div></div>""" % (
                step.tool_id,
                step.tool_id,
            )
            step_dict = {
                "id": step.order_index,
                "type": "invalid",
                "tool_id": step.tool_id,
                "name": "Unrecognized Tool: %s" % step.tool_id,
                "tool_state": None,
                "tooltip": None,
                "tool_errors": ["Unrecognized Tool Id: %s" % step.tool_id],
                "data_inputs": [],
                "data_outputs": [],
                "form_html": invalid_tool_form_html,
                "annotation": annotation_str,
                "input_connections": {},
                "post_job_actions": {},
                "uuid": str(step.uuid),
                "label": step.label or None,
                "workflow_outputs": [],
            }
            # Position
            step_dict["position"] = step.position
            # Add to return value
            data["steps"][step.order_index] = step_dict
            continue
        # Fix any missing parameters
        upgrade_message = module.check_and_update_state()
        if upgrade_message:
            # FIXME: Frontend should be able to handle workflow messages
            #        as a dictionary not just the values
            data["upgrade_messages"][step.order_index] = upgrade_message.values()
        # Get user annotation.
        step_annotation = self.get_item_annotation_obj(
            trans.sa_session, trans.user, step
        )
        annotation_str = ""
        if step_annotation:
            annotation_str = step_annotation.annotation
        form_html = None
        if trans.history:
            # If in a web session, attach form html. No reason to do
            # so for API requests.
            form_html = module.get_config_form()
        # Pack attributes into plain dictionary
        step_dict = {
            "id": step.order_index,
            "type": module.type,
            "tool_id": module.get_tool_id(),
            "name": module.get_name(),
            "tool_state": module.get_state(),
            "tooltip": module.get_tooltip(static_path=url_for("/static")),
            "tool_errors": module.get_errors(),
            "data_inputs": module.get_data_inputs(),
            "data_outputs": module.get_data_outputs(),
            "form_html": form_html,
            "annotation": annotation_str,
            "post_job_actions": {},
            "uuid": str(step.uuid) if step.uuid else None,
            "label": step.label or None,
            "workflow_outputs": [],
        }
        # Connections
        input_connections = step.input_connections
        input_connections_type = {}
        multiple_input = {}  # Boolean value indicating if this can be mutliple
        if step.type is None or step.type == "tool":
            # Determine full (prefixed) names of valid input datasets
            data_input_names = {}

            def callback(input, value, prefixed_name, prefixed_label):
                if isinstance(input, DataToolParameter) or isinstance(
                    input, DataCollectionToolParameter
                ):
                    data_input_names[prefixed_name] = True
                    multiple_input[prefixed_name] = input.multiple
                    if isinstance(input, DataToolParameter):
                        input_connections_type[input.name] = "dataset"
                    if isinstance(input, DataCollectionToolParameter):
                        input_connections_type[input.name] = "dataset_collection"

            visit_input_values(module.tool.inputs, module.state.inputs, callback)
            # Filter
            # FIXME: this removes connection without displaying a message currently!
            input_connections = [
                conn
                for conn in input_connections
                if conn.input_name in data_input_names
            ]
            # post_job_actions
            pja_dict = {}
            for pja in step.post_job_actions:
                pja_dict[pja.action_type + pja.output_name] = dict(
                    action_type=pja.action_type,
                    output_name=pja.output_name,
                    action_arguments=pja.action_arguments,
                )
            step_dict["post_job_actions"] = pja_dict
            # workflow outputs
            outputs = []
            for output in step.workflow_outputs:
                outputs.append(output.output_name)
            step_dict["workflow_outputs"] = outputs
        # Encode input connections as dictionary
        input_conn_dict = {}
        for conn in input_connections:
            input_type = "dataset"
            if conn.input_name in input_connections_type:
                input_type = input_connections_type[conn.input_name]
            conn_dict = dict(
                id=conn.output_step.order_index,
                output_name=conn.output_name,
                input_type=input_type,
            )
            if conn.input_name in multiple_input:
                if conn.input_name in input_conn_dict:
                    input_conn_dict[conn.input_name].append(conn_dict)
                else:
                    input_conn_dict[conn.input_name] = [conn_dict]
            else:
                input_conn_dict[conn.input_name] = conn_dict
        step_dict["input_connections"] = input_conn_dict
        # Position
        step_dict["position"] = step.position
        # Add to return value
        data["steps"][step.order_index] = step_dict
    return data