def output_principals()

in tools/state_iam.py [0:0]


def output_principals(bindings):
  'Output bindings in Markdown format by principals.'
  resource_grouper = itertools.groupby(
      bindings, key=lambda b: (b.resource_type, b.resource_id))
  print('# IAM bindings reference')
  print('\nLegend: <code>+</code> additive, <code>•</code> conditional.')
  for resource, resource_groups in resource_grouper:
    resource_type, resource_name = resource
    print(f'\n## {resource_type.title()} <i>{resource_name.lower()}</i>\n')
    principal_grouper = itertools.groupby(
        resource_groups, key=lambda b: (b.member_type, b.member_id))
    print('| members | roles |')
    print('|---|---|')
    for principal, principal_groups in principal_grouper:
      roles = []
      for b in principal_groups:
        additive = '<code>+</code>' if not b.authoritative else ''
        conditions = '<code>•</code>' if b.conditions else ''
        if b.role.startswith('organizations/'):
          roles.append(f'{b.role} {additive}{conditions}')
        else:
          url = ('https://cloud.google.com/iam/docs/understanding-roles#'
                 f'{b.role.replace("roles/", "")}')
          roles.append(f'[{b.role}]({url}) {additive}{conditions}')
      print(f'|<b>{principal[1]}</b><br><small><i>{principal[0]}</i></small>|'
            f'{"<br>".join(roles)}|')