docs: def validate_df(df, dm, con=None):
      """
      Take in a DataFrame and corresponding data model.
      Run all validations for that DataFrame.
      Output is the original DataFrame with some new columns
      that contain the validation output.
      Validation columns start with:
      presence_pass_ (checking that req'd columns are present)
      type_pass_  (checking that the data is of the correct type)
      value_pass_ (checking that the value is within the appropriate range)
      group_pass_ (making sure that group validations pass)
      """
      # check column validity
      required_one = {}  # keep track of req'd one in group validations here
      cols = df.columns
      invalid_cols = [col for col in cols if col not in dm.index]
      # go through and run all validations for the data type
      for validation_name, validation in dm.iterrows():
          value_type = validation['type']
          if validation_name in df.columns:
              output = df[validation_name].apply(test_type, args=(value_type,))
              df["type_pass" + "_" + validation_name + "_" + value_type] = output
          #
          val_list = validation['validations']
          if not val_list or isinstance(val_list, float):
              continue
          for num, val in enumerate(val_list):
              func_name, arg = split_func(val)
              if arg == "magic_table_column":
                  continue
              # first validate for presence
              if func_name in presence_operations:
                  func = presence_operations[func_name]
                  #grade = func(validation_name, df, arg, dm)
                  grade = func(validation_name, arg, dm, df, con)
                  pass_col_name = "presence_pass_" + validation_name + "_" + func.__name__
                  df[pass_col_name] = grade
              # then validate for correct values
              elif func_name in value_operations:
                  func = value_operations[func_name]
                  if validation_name in df.columns:
                      grade = df.apply(func, args=(validation_name, arg, dm, df, con), axis=1)
                      col_name = "value_pass_" + validation_name + "_" + func.__name__
                      if col_name in df.columns:
                          num_range = list(range(1, 10))
                          for num in num_range:
                              if (col_name + str(num)) in df.columns:
                                  continue
                              else:
                                  col_name = col_name + str(num)
                                  break
                      df[col_name] = grade.astype(object)
              # last, validate at the column group level
              elif func_name in group_operations:
                  func = group_operations[func_name]
                  missing = func(validation_name, arg, dm, df)
                  if arg not in required_one:
                      required_one[arg] = [missing]
                  else:
                      required_one[arg].append(missing)
          # format the group validation columns
          for key, value in list(required_one.items()):
              if None in value:
                  # this means at least one value from the required group is present,
                  # so the validation passes
                  continue
              else:
                  # otherwise, all of the values from the required group are missing,
                  # so the validation fails
                  df["group_pass_{}".format(key)] = "you must have one column from group {}: {}".format(key, ", ".join(value))
  
      return df