docs: def generate_circle_output():
      """Build sequence for Circle CI 2.0 config.yml
  
      builds the circleci structure
      also links individual jobs into a workflow graph
      """
      base = new_base()
      workflow = networkx.DiGraph()
      LOG.info('%s python versions', len(python_versions))
      LOG.info('%s mbed cloud hosts', len(mbed_cloud_hosts))
  
      job, content = new_tpip()
      base['jobs'].update({job: content})
      workflow.add_node(job)
  
      job, content = new_newscheck()
      base['jobs'].update({job: content})
      workflow.add_node(
          job,
          workflow=dict(
              filters=dict(
                  branches=dict(
                      # we ignore this check for builds directly on the base branches
                      ignore=['master', 'integration']
                  )
              )
          )
      )
  
      job, content = new_build_documentation()
      base['jobs'].update({job: content})
      workflow.add_node(
          job,
          workflow=dict(
              requires=['build_py2', 'build_py3'],
              filters = dict(
                  branches=dict(
                      # Only update the documentation on release branches
                      only=['master', 'beta']
          )
      )
      )
      )
  
      preload_job, content = new_preload()
      base['jobs'].update({preload_job: content})
      workflow.add_node(job)
  
      for py_ver in python_versions.values():
          build_job, build_content = new_build(py_ver=py_ver)
          base['jobs'].update({build_job: build_content})
          workflow.add_edge(preload_job, build_job)
  
          for cloud_host in mbed_cloud_hosts.values():
              test_job, test_content = new_test(py_ver=py_ver, cloud_host=cloud_host)
              base['jobs'].update({test_job: test_content})
              workflow.add_edge(build_job, test_job)
  
      for release_target in release_target_map.values():
          deploy_job, deploy_content = new_deploy(
              py_ver=python_versions['three'],
              release_target=release_target
          )
          base['jobs'].update({deploy_job: deploy_content})
  
      # wire up the release gates (clicky buttons)
      workflow.add_edge(
          test_name(python_versions['three'], mbed_cloud_hosts['osii']),
          release_name(release_target_map['beta']),
          type='approval',
      )
      workflow.add_edge(
          test_name(python_versions['three'], mbed_cloud_hosts['production']),
          release_name(release_target_map['prod']),
          type='approval',
          filters=dict(branches=dict(only='master')),
      )
      workflow.add_edge(
          test_name(python_versions['two'], mbed_cloud_hosts['production']),
          release_name(release_target_map['prod']),
      )
  
      # we only want to deploy in certain conditions
      workflow.add_edge(
          release_name(release_target_map['beta']),
          deploy_name(python_versions['three'], release_target_map['beta'])
      )
  
      workflow.add_edge(
          release_name(release_target_map['prod']),
          deploy_name(python_versions['three'], release_target_map['prod'])
      )
  
      workflow_jobs = base['workflows']['python_sdk_workflow']['jobs']
  
      # build the workflow graph
      for job_name in networkx.topological_sort(workflow):
          job_config = {}
          per_node_config = workflow.nodes[job_name].get('workflow')
          if per_node_config:
              job_config.update(per_node_config)
          workflow_jobs.append({job_name: job_config})
          for edge in workflow.in_edges(job_name):
              job_config.update(workflow.get_edge_data(*edge))
              job_config.setdefault('requires', []).append(edge[0])
  
      LOG.info('%s circle jobs', len(base['jobs']))
      return dict(base)