docs: def get_magic_info(self, child_type, parent_type=None, attr='er',
                         filename=None, sort_by_file_type=False):
          """
          Read er_*.txt or pmag_*.txt file.
          If no filename is provided, use er_* or pmag_* file in WD.
          If sort_by_file_type, use file header to determine child, parent types,
          instead of passing those in as arguments.
          Once file is open, parse information into dictionaries for each item.
          If the item does not yet exist, add it to the builder data object.
          Then add info to the item object as object.er_data or object.pmag_data.
          """
          parent = ''
          grandparent_type = None
          magic_name = 'er_' + child_type + '_name'
          expected_item_type = child_type
          if not filename:
              short_filename = attr + '_' + child_type + 's.txt'
              magic_file = os.path.join(self.WD, short_filename)
          else:
              short_filename = os.path.split(filename)[1]
              magic_file = filename
              attr = short_filename.split('_')[0]
          print('-I- Attempting to read {}'.format(magic_file))
          if not os.path.isfile(magic_file):
              print('-W- Could not find {}'.format(magic_file))
              return False
          # get the data from the appropriate .txt file
  
          data_dict, header, file_type = self.read_magic_file(magic_file, magic_name,
                                                              sort_by_file_type=sort_by_file_type)
          if not data_dict:
              print('-W- Could not read in file: {}.\n    Make sure it is a MagIC-format file'.format(magic_file))
              return False
  
          item_type = file_type.split('_')[1][:-1]
          # if a file was named wrong, use the type of data that is actually in that file
          if item_type != expected_item_type:
              print('-W- Expected data of type: {} but instead got: {}'.format(expected_item_type,
                                                                               item_type))
              print('-W- Using type: {}'.format(item_type))
              if item_type == 'age':
                  self.get_age_info(filename)
                  return 'age'
              child_type = item_type
              magic_name = 'er_' + child_type + '_name'
              ind = self.ancestry.index(child_type)
              parent_type = self.ancestry[ind+1]
              if item_type != 'location':
                  grandparent_type = self.ancestry[ind+2]
              else:
                  grandparent_type = ''
          if not grandparent_type:
              ind = self.ancestry.index(child_type)
              try:
                  grandparent_type = self.ancestry[ind+2]
              except IndexError:
                  grandparent_type = None
          child_list, child_class, child_constructor = self.data_lists[child_type]
  
          if parent_type:
              parent_list, parent_class, parent_constructor = self.data_lists[parent_type]
          else:
              parent_list, parent_name = None, None
          for child_name in data_dict:
              # if there is a possible parent, try to find parent object in the data model
              if parent_type:
                  parent_name = data_dict[child_name].get('er_' + parent_type + '_name', '')
                  parent = self.find_by_name(parent_name, parent_list)
                  if parent:
                      remove_dict_headers(parent.er_data)
                      remove_dict_headers(parent.pmag_data)
              # if there should be a parent
              # (meaning there is a name for it and the child object should have a parent)
              # but none exists in the data model, go ahead and create that parent object.
              if parent_name and parent_type and not parent:
                  # try to get grandparent
                  grandparent = None
                  grandparent_name = None
                  if grandparent_type:
                      grandparent_list, grandparent_class, grandparent_constructor = self.data_lists[grandparent_type]
                      grandparent_name = data_dict[child_name]['er_' + grandparent_type + '_name']
                      grandparent = self.find_by_name(grandparent_name, grandparent_list)
                      if grandparent_name and not grandparent:
                          grandparent = grandparent_constructor(grandparent_name, None)
                  parent = parent_constructor(parent_name, grandparent_name)
              # otherwise there is no parent and none can be created, so use an empty string
              elif not parent:
                  parent_name = None
                  parent = ''
              child = self.find_by_name(child_name, child_list)
              # if the child object does not exist yet in the data model
              if not child:
                  child = child_constructor(child_name, parent_name)
              else:
                  # bind parent to child and child to parent
                  if parent:
                      child.set_parent(parent)
                  if parent and (child not in parent.children):
                      parent.add_child(child)
  
              # add in the appropriate data dictionary to the child object
              if attr == 'er':
                  self.update_methods[child_type](child_name, child_name, parent_name,
                                                  new_er_data=data_dict[child_name])
              else:
                  self.update_methods[child_type](child_name, child_name, parent_name,
                                                  new_pmag_data=data_dict[child_name])
              # old way
              #child.__setattr__(attr + '_data', data_dict[child_name])
              remove_dict_headers(child.er_data)
              remove_dict_headers(child.pmag_data)
              #
          return child_type