docs: def dict_from_mmcif(mmcif, path=True):
      """Parse mmcif file into a dictionary.
  
      Notes
      -----
      Full list of keys/value types, and further information on them can be viewed here:
              http://mmcif.wwpdb.org/docs/pdb_to_pdbx_correspondences.html
      All values in the returned dict are str or list(str).
      This means that some of the data values are string representations of integers
      - parse these outside of this function if desired.
      An alternative approach to this can be found in Biopython (via the function Bio.PDB.MMCIF2Dict.MMCIF2Dict).
      mmcif files are subject to the usual "here be dragons" problems of the PDB and difficult file formats.
      As such, this function is likely to be in a permanent state of flux as more dragons are found.
  
      Parameters
      ----------
      mmcif : str
          mmcif string or a path to an mmcif file.
      path : bool
          True if mmcif is a path.
  
      Returns
      -------
      cif_data : dict
          Keys are cif data names, e.g. '_struct_keywords.text'.
          Values are str or list(str).
  
      """
      if path:
          with open(mmcif, 'r') as foo:
              lines = foo.readlines()
      else:
          lines = mmcif.splitlines()
      lines = [' '.join(x.strip().split()) for x in lines]
  
      # Some of the data in a .cif files are stored between 'loop_' to initiate a loop, and '#' to terminate it.
      # The variable 'loop' is a flag to keep track of this behaviour.
      loop = False
  
      # Set up the dictionary to populate as the lines of the .cif file are iterated over.
      cif_data = {}
  
      for i, line in enumerate(lines):
  
          if not line:
              continue
  
          # hash signifies end of a loop. Ensure loop flag is set to False.
          if line == '#':
              loop = False
              continue
  
          if not loop:
              # This line initiates a loop section, in which keys are listed first,
              # followed by lines of data in which the values are listed in the same order as the above keys.
              # The values in the loop section will be stored as lists - there are multiple values for one key.
              # An example of this type of data is the 'REVDAT' section, which stores details on the (potentially
              # numerous) various revisions made to the PDB file during its history.
  
              if line[:5] == 'loop_':
                  loop = True
                  key_list = []
                  continue
  
              # Lines beginning with '_' start with data names, i.e. keys in the cif_data dictionary.
              elif line[0] == '_':
                  # If line consists only of a key, then subsequent lines may contain the associated value.
                  if len(line.split()) == 1:
                      current_key = line
                      count = 1
                      while True:
                          # Look forward until a key is found, keeping count of the number of lines in between.
                          try:
                              if lines[i + count][0] != '_':
                                  count += 1
  
                              # prevent infinite loop.
                              elif i + count > len(lines):
                                  break
  
                              else:
                                  if count > 1:
                                      try:
                                          cif_data[current_key] = ' '.join(lines[i + 1: i + count])
                                      except IndexError:
                                          cif_data[current_key] = None
                                  else:
                                      cif_data[current_key] = None
                                  break
                          except IndexError:
                              break
                      continue
  
                  # Simplest case. Line is a key-value pair, with the key identified by its first character, '_'.
                  elif len(line.split()) > 1:
                      line = line.split()
                      try:
                          cif_data[line[0]] = ' '.join(line[1:])
                      except IndexError:
                          cif_data[line[0]] = None
                      continue
  
              # Line is one of multiple lines that are combined into a value in the while True: loop above.
              else:
                  continue
  
          else:
              # Within a loop section, keys are identified by their first character '_'.
              # Add them to the list of keys in the loop.
              if line[0] == '_':
                  if len(line.split()) == 1:
                      key_list.append(line)
                      if line not in cif_data.keys():
                          cif_data[line] = []
  
              # Within a loop section, the values are listed within a single space-separated line in the same order
              # that the keys were listed at the start of the loop.
              else:
                  # Cannot do a simple split if any of the values themselves are strings containing at least one space.
                  if '\"' in line and line.count('\"') % 2 == 0:
                      line_parts = [x.strip() for x in line.split('\"') if x]
                      line = []
                      for part in line_parts:
                          if line_parts.index(part) % 2 == 0:
                              for x in part.split():
                                  line.append(x)
                          else:
                              line.append(part)
  
                  elif '\'' in line and line.count('\'') % 2 == 0:
                      line = [x.strip() for x in line.split('\'') if x]
  
                  elif len(key_list) == len(line.split()):
                      line = line.split()
  
                  if len(key_list) == len(line):
                      for j, v in enumerate(line):
                          cif_data[key_list[j]].append(line[j])
                  else:
                      # CURRENTLY THERE IS A PROBLEM WITH REALLY LONG LOOPS eg _pdbx_refine_tls*, _pdbx_struct_oper_list*
                      # The values span multiple lines, and therefore do not satisfy
                      # the condition of the above 'if' statement.
                      # A correction for this needs to keep track of the value count on subsequent lines,
                      # until the 'if' condition is met.
                      continue
  
      return cif_data