nodes: 0, module; 1, function_definition; 2, function_name:parse_name; 3, parameters; 4, block; 5, identifier:name; 6, expression_statement; 7, expression_statement; 8, if_statement; 9, try_statement; 10, comment:# Check that no OIDs not in MULTIPLE_OIDS occur more then once; 11, for_statement; 12, return_statement; 13, comment:"""Parses a subject string as used in OpenSSLs command line utilities.
  
      The ``name`` is expected to be close to the subject format commonly used by OpenSSL, for example
      ``/C=AT/L=Vienna/CN=example.com/emailAddress=user@example.com``. The function does its best to be lenient
      on deviations from the format, object identifiers are case-insensitive (e.g. ``cn`` is the same as ``CN``,
      whitespace at the start and end is stripped and the subject does not have to start with a slash (``/``).
  
      >>> parse_name('/CN=example.com')
      [('CN', 'example.com')]
      >>> parse_name('c=AT/l= Vienna/o="ex org"/CN=example.com')
      [('C', 'AT'), ('L', 'Vienna'), ('O', 'ex org'), ('CN', 'example.com')]
  
      Dictionary keys are normalized to the values of :py:const:`OID_NAME_MAPPINGS` and keys will be sorted
      based on x509 name specifications regardless of the given order:
  
      >>> parse_name('L="Vienna / District"/EMAILaddress=user@example.com')
      [('L', 'Vienna / District'), ('emailAddress', 'user@example.com')]
      >>> parse_name('/C=AT/CN=example.com') == parse_name('/CN=example.com/C=AT')
      True
  
      Due to the magic of :py:const:`NAME_RE`, the function even supports quoting strings and including slashes,
      so strings like ``/OU="Org / Org Unit"/CN=example.com`` will work as expected.
  
      >>> parse_name('L="Vienna / District"/CN=example.com')
      [('L', 'Vienna / District'), ('CN', 'example.com')]
  
      But note that it's still easy to trick this function, if you really want to. The following example is
      *not* a valid subject, the location is just bogus, and whatever you were expecting as output, it's
      certainly different:
  
      >>> parse_name('L="Vienna " District"/CN=example.com')
      [('L', 'Vienna'), ('CN', 'example.com')]
  
      Examples of where this string is used are:
  
      .. code-block:: console
  
          # openssl req -new -key priv.key -out csr -utf8 -batch -sha256 -subj '/C=AT/CN=example.com'
          # openssl x509 -in cert.pem -noout -subject -nameopt compat
          /C=AT/L=Vienna/CN=example.com
      """; 14, assignment; 15, not_operator; 16, comment:# empty subjects are ok; 17, block; 18, block; 19, except_clause; 20, pattern_list; 21, call; 22, block; 23, call; 24, identifier:name; 25, call; 26, identifier:name; 27, return_statement; 28, expression_statement; 29, as_pattern; 30, block; 31, identifier:key; 32, identifier:oid; 33, attribute; 34, argument_list; 35, if_statement; 36, identifier:sort_name; 37, argument_list; 38, attribute; 39, argument_list; 40, list; 41, assignment; 42, identifier:KeyError; 43, as_pattern_target; 44, raise_statement; 45, identifier:NAME_OID_MAPPINGS; 46, identifier:items; 47, boolean_operator; 48, block; 49, identifier:items; 50, identifier:name; 51, identifier:strip; 52, identifier:items; 53, list_comprehension; 54, identifier:e; 55, call; 56, comparison_operator:sum(1 for t in items if t[0] == key) > 1; 57, comparison_operator:oid not in MULTIPLE_OIDS; 58, raise_statement; 59, tuple; 60, for_in_clause; 61, identifier:ValueError; 62, argument_list; 63, call; 64, integer:1; 65, identifier:oid; 66, identifier:MULTIPLE_OIDS; 67, call; 68, subscript; 69, call; 70, identifier:t; 71, call; 72, binary_operator:'Unknown x509 name field: %s' % e.args[0]; 73, identifier:sum; 74, generator_expression; 75, identifier:ValueError; 76, argument_list; 77, identifier:NAME_CASE_MAPPINGS; 78, call; 79, identifier:force_text; 80, argument_list; 81, attribute; 82, argument_list; 83, string; 84, subscript; 85, integer:1; 86, for_in_clause; 87, if_clause; 88, binary_operator:'Subject contains multiple "%s" fields' % key; 89, attribute; 90, argument_list; 91, subscript; 92, identifier:NAME_RE; 93, identifier:findall; 94, identifier:name; 95, string_content:Unknown x509 name field: %s; 96, attribute; 97, integer:0; 98, identifier:t; 99, identifier:items; 100, comparison_operator:t[0] == key; 101, string:'Subject contains multiple "%s" fields'; 102, identifier:key; 103, subscript; 104, identifier:upper; 105, identifier:t; 106, integer:2; 107, identifier:e; 108, identifier:args; 109, subscript; 110, identifier:key; 111, identifier:t; 112, integer:0; 113, identifier:t; 114, integer:0
code: def parse_name(name):
      """Parses a subject string as used in OpenSSLs command line utilities.
  
      The ``name`` is expected to be close to the subject format commonly used by OpenSSL, for example
      ``/C=AT/L=Vienna/CN=example.com/emailAddress=user@example.com``. The function does its best to be lenient
      on deviations from the format, object identifiers are case-insensitive (e.g. ``cn`` is the same as ``CN``,
      whitespace at the start and end is stripped and the subject does not have to start with a slash (``/``).
  
      >>> parse_name('/CN=example.com')
      [('CN', 'example.com')]
      >>> parse_name('c=AT/l= Vienna/o="ex org"/CN=example.com')
      [('C', 'AT'), ('L', 'Vienna'), ('O', 'ex org'), ('CN', 'example.com')]
  
      Dictionary keys are normalized to the values of :py:const:`OID_NAME_MAPPINGS` and keys will be sorted
      based on x509 name specifications regardless of the given order:
  
      >>> parse_name('L="Vienna / District"/EMAILaddress=user@example.com')
      [('L', 'Vienna / District'), ('emailAddress', 'user@example.com')]
      >>> parse_name('/C=AT/CN=example.com') == parse_name('/CN=example.com/C=AT')
      True
  
      Due to the magic of :py:const:`NAME_RE`, the function even supports quoting strings and including slashes,
      so strings like ``/OU="Org / Org Unit"/CN=example.com`` will work as expected.
  
      >>> parse_name('L="Vienna / District"/CN=example.com')
      [('L', 'Vienna / District'), ('CN', 'example.com')]
  
      But note that it's still easy to trick this function, if you really want to. The following example is
      *not* a valid subject, the location is just bogus, and whatever you were expecting as output, it's
      certainly different:
  
      >>> parse_name('L="Vienna " District"/CN=example.com')
      [('L', 'Vienna'), ('CN', 'example.com')]
  
      Examples of where this string is used are:
  
      .. code-block:: console
  
          # openssl req -new -key priv.key -out csr -utf8 -batch -sha256 -subj '/C=AT/CN=example.com'
          # openssl x509 -in cert.pem -noout -subject -nameopt compat
          /C=AT/L=Vienna/CN=example.com
      """
      name = name.strip()
      if not name:  # empty subjects are ok
          return []
  
      try:
          items = [(NAME_CASE_MAPPINGS[t[0].upper()], force_text(t[2])) for t in NAME_RE.findall(name)]
      except KeyError as e:
          raise ValueError('Unknown x509 name field: %s' % e.args[0])
  
      # Check that no OIDs not in MULTIPLE_OIDS occur more then once
      for key, oid in NAME_OID_MAPPINGS.items():
          if sum(1 for t in items if t[0] == key) > 1 and oid not in MULTIPLE_OIDS:
              raise ValueError('Subject contains multiple "%s" fields' % key)
  
      return sort_name(items)