docs: def get_age_info(self, filename=None):
          """
          Read er_ages.txt file.
          Parse information into dictionaries for each site/sample.
          Then add it to the site/sample object as site/sample.age_data.
          """
          # use filename if provided, otherwise find er_ages.txt in WD
          if not filename:
              short_filename = 'er_ages.txt'
              magic_file = os.path.join(self.WD, short_filename)
          else:
              magic_file = filename
          if not os.path.isfile(magic_file):
              print('-W- Could not find {}'.format(magic_file))
              return False
  
          data_dict, header, file_type = self.read_magic_file(magic_file, 'by_line_number')
          # if provided file is not an age_file,
          # try to read it in as whatever type of file it actually is
          if file_type != 'er_ages':
              item_type = file_type.split('_')[1][:-1]
              self.get_magic_info(item_type, filename=filename, sort_by_file_type=True)
              return file_type
  
          # if it is an age file,
          # determine level for each age and assign it to the appropriate pmag object
          for item_dict in list(data_dict.values()):
              item_type = None
              for dtype in ['specimen', 'sample', 'site', 'location']:
                  header_name = 'er_' + dtype + '_name'
                  if header_name in list(item_dict.keys()):
                      if item_dict[header_name]:
                          item_type = dtype
                          item_name = item_dict[header_name].strip()
                          break
              if not item_type:
                  print('-W- You must provide a name for your age')
                  print('    These data:\n{}\n    will not be imported'.format(item_dict))
                  continue
              items_list = self.data_lists[item_type][0]
              item = self.find_by_name(item_name, items_list)
              if not item:
                  ## the following code creates any item in er_ages that does not exist already
                  ## however, we may not WANT that behavior
                  print("""-I- A {} named {} in your age file was not found in the data object:
      Now initializing {} {}""".format(item_type, item_name, item_type, item_name))
                  ind = self.ancestry.index(item_type)
                  parent_type = self.ancestry[ind+1]
                  parent_header, parent_constructor = None, None
                  if parent_type:
                      parent_list, parent_class, parent_constructor = self.data_lists[parent_type]
                      parent_header = 'er_' + parent_type + '_name'
                  parent_name = item_dict.get(parent_header, '')
                  parent = self.find_by_name(parent_name, parent_list)
                  # if the parent item doesn't exist, and should, create it
                  if parent_name and not parent:
                      print("""-I- A {} named {} in your age file was not found in the data object:
      Now initializing {} {}""".format(parent_type, parent_name, parent_type, parent_name))
                      parent = parent_constructor(parent_name, None)
                  item_constructor = self.data_lists[item_type][2]
                  if not parent:
                      parent_name = None
                  item = item_constructor(item_name, parent_name)
              # add the age data to the object
              item.age_data = remove_dict_headers(item_dict)
          # note that data is available to write
          self.write_ages = True
          return file_type