code: def _enforce_schema(pf_input: PyFuncInput, input_schema: Schema):
      """
      Enforces the provided input matches the model's input schema,
  
      For signatures with input names, we check there are no missing inputs and reorder the inputs to
      match the ordering declared in schema if necessary. Any extra columns are ignored.
  
      For column-based signatures, we make sure the types of the input match the type specified in
      the schema or if it can be safely converted to match the input schema.
  
      For tensor-based signatures, we make sure the shape and type of the input matches the shape
      and type specified in model's input schema.
      """
  
      def _is_scalar(x):
          return np.isscalar(x) or x is None
  
      if isinstance(pf_input, pd.Series):
          pf_input = pd.DataFrame(pf_input)
      if not input_schema.is_tensor_spec():
          # convert single DataType to pandas DataFrame
          if np.isscalar(pf_input):
              pf_input = pd.DataFrame([pf_input])
          elif isinstance(pf_input, dict):
              # keys are column names
              if any(
                  isinstance(col_spec.type, (Array, Object))
                  for col_spec in input_schema.inputs
              ) or all(
                  _is_scalar(value)
                  or (
                      isinstance(value, list)
                      and all(isinstance(item, str) for item in value)
                  )
                  for value in pf_input.values()
              ):
                  pf_input = pd.DataFrame([pf_input])
              else:
                  try:
                      # This check is specifically to handle the serving structural cast for
                      # certain inputs for the transformers implementation. Due to the fact that
                      # specific Pipeline types in transformers support passing input data
                      # of the form Dict[str, str] in which the value is a scalar string, model
                      # serving will cast this entry as a numpy array with shape () and size 1.
                      # This is seen as a scalar input when attempting to create a Pandas
                      # DataFrame from such a numpy structure and requires the array to be
                      # encapsulated in a list in order to prevent a ValueError exception for
                      # requiring an index if passing in all scalar values thrown by Pandas.
                      if all(
                          isinstance(value, np.ndarray)
                          and value.dtype.type == np.str_
                          and value.size == 1
                          and value.shape == ()
                          for value in pf_input.values()
                      ):
                          pf_input = pd.DataFrame([pf_input])
                      elif any(
                          isinstance(value, np.ndarray)
                          and value.ndim > 1
                          for value in pf_input.values()
                      ):
                          # Pandas DataFrames can't be constructed with embedded multi-dimensional
                          # numpy arrays. Accordingly, we convert any multi-dimensional numpy
                          # arrays to lists before constructing a DataFrame. This is safe because
                          # ColSpec model signatures do not support array columns, so subsequent
                          # validation logic will result in a clear "incompatible input types"
                          # exception. This is preferable to a pandas DataFrame construction error
                          pf_input = pd.DataFrame(
                              {
                                  key: (
                                      value.tolist()
                                      if (
                                          isinstance(value, np.ndarray)
                                          and value.ndim > 1
                                      )
                                      else value
                                  )
                                  for key, value in pf_input.items()
                              }
                          )
                      else:
                          pf_input = pd.DataFrame(pf_input)
                  except Exception as e:
                      raise MlflowException(
                          "This model contains a column-based signature, which suggests a DataFrame"
                          " input. There was an error casting the input data to a DataFrame:"
                          f" {e}"
                      )
          elif isinstance(pf_input, (list, np.ndarray, pd.Series)):
              pf_input = pd.DataFrame(pf_input)
  
          if not isinstance(pf_input, pd.DataFrame):
              raise MlflowException(
                  f"Expected input to be DataFrame. Found: {type(pf_input).__name__}"
              )
  
      if input_schema.has_input_names():
          # make sure there are no missing columns
          input_names = input_schema.required_input_names()
          optional_names = input_schema.optional_input_names()
          expected_required_cols = set(input_names)
          actual_cols = set()
          optional_cols = set(optional_names)
          if len(expected_required_cols) == 1 and isinstance(
              pf_input, np.ndarray
          ):
              # for schemas with a single column, match input with column
              pf_input = {input_names[0]: pf_input}
              actual_cols = expected_required_cols
          elif isinstance(pf_input, pd.DataFrame):
              actual_cols = set(pf_input.columns)
          elif isinstance(pf_input, dict):
              actual_cols = set(pf_input.keys())
          missing_cols = expected_required_cols - actual_cols
          extra_cols = (
              actual_cols - expected_required_cols - optional_cols
          )
          # Preserve order from the original columns, since missing/extra columns are likely to
          # be in same order.
          missing_cols = [c for c in input_names if c in missing_cols]
          extra_cols = [c for c in actual_cols if c in extra_cols]
          if missing_cols:
              message = f"Model is missing inputs {missing_cols}."
              if extra_cols:
                  message += f" Note that there were extra inputs: {extra_cols}"
              raise MlflowException(message)
      elif not input_schema.is_tensor_spec():
          # The model signature does not specify column names => we can only verify column count.
          num_actual_columns = len(pf_input.columns)
          if num_actual_columns < len(input_schema.inputs):
              raise MlflowException(
                  "Model inference is missing inputs. The model signature declares "
                  "{} inputs  but the provided value only has "
                  "{} inputs. Note: the inputs were not named in the signature so we can "
                  "only verify their count.".format(
                      len(input_schema.inputs), num_actual_columns
                  )
              )
      if input_schema.is_tensor_spec():
          return _enforce_tensor_schema(pf_input, input_schema)
      elif input_schema.has_input_names():
          return _enforce_named_col_schema(pf_input, input_schema)
      else:
          return _enforce_unnamed_col_schema(pf_input, input_schema)
  
imports: import datetime
  import decimal
  import json
  import logging
  import os
  from copy import deepcopy
  from typing import Any, Dict, List, Optional, Union
  import numpy
  import pandas
  from mlflow.exceptions import INVALID_PARAMETER_VALUE, MlflowException
  from mlflow.models import Model
  from mlflow.store.artifact.utils.models import get_model_name_and_version
  from mlflow.types import DataType, ParamSchema, ParamSpec, Schema, TensorSpec
  from mlflow.types.schema import Array, Object, Property
  from mlflow.types.utils import TensorsNotSupportedException, _infer_param_schema, clean_tensor_type
  from mlflow.utils.annotations import experimental
  from mlflow.utils.proto_json_utils import NumpyEncoder, dataframe_from_parsed_json, parse_tf_serving_input
  from mlflow.utils.uri import get_databricks_profile_uri_from_artifact_uri
label_desc: Use image node_id 15 for calling a global function with example usage: _enforce_schema(pf_input, input_schema) and returns: unknown, _enforce_tensor_schema, _enforce_named_col_schema, _enforce_unnamed_col_schema