code: def _conditional_join_preliminary_checks(
      df: pd.DataFrame,
      right: Union[pd.DataFrame, pd.Series],
      conditions: tuple,
      how: str,
      sort_by_appearance: bool,
      df_columns: Any,
      right_columns: Any,
      keep: str,
      use_numba: bool,
      indicator: Union[bool, str],
      force: bool,
      return_matching_indices: bool = False,
  ) -> tuple:
      """
      Preliminary checks for conditional_join are conducted here.
  
      Checks include differences in number of column levels,
      length of conditions, existence of columns in dataframe, etc.
      """
  
      check("right", right, [pd.DataFrame, pd.Series])
  
      df = df[:]
      right = right[:]
  
      if isinstance(right, pd.Series):
          if not right.name:
              raise ValueError(
                  "Unnamed Series are not supported for conditional_join."
              )
          right = right.to_frame()
  
      if df.columns.nlevels != right.columns.nlevels:
          raise ValueError(
              "The number of column levels "
              "from the left and right frames must match. "
              "The number of column levels from the left dataframe "
              f"is {df.columns.nlevels}, while the number of column levels "
              f"from the right dataframe is {right.columns.nlevels}."
          )
  
      if not conditions:
          raise ValueError(
              "Kindly provide at least one join condition."
          )
  
      conditions = [
          cond.join_args if isinstance(cond, col) else cond
          for cond in conditions
      ]
      for condition in conditions:
          check("condition", condition, [tuple])
          len_condition = len(condition)
          if len_condition != 3:
              raise ValueError(
                  "condition should have only three elements; "
                  f"{condition} however is of length {len_condition}."
              )
  
      for left_on, right_on, op in conditions:
          check("left_on", left_on, [Hashable])
          check("right_on", right_on, [Hashable])
          check("operator", op, [str])
          check_column(df, [left_on])
          check_column(right, [right_on])
          _check_operator(op)
  
      if (
          all(
              (
                  op == _JoinOperator.STRICTLY_EQUAL.value
                  for *_, op in conditions
              )
          )
          and not return_matching_indices
      ):
          raise ValueError("Equality only joins are not supported.")
  
      check("how", how, [str])
  
      if how not in {"inner", "left", "right", "outer"}:
          raise ValueError(
              "'how' should be one of 'inner', 'left', 'right' or 'outer'."
          )
  
      if sort_by_appearance:
          warnings.warn(
              "The keyword argument "
              "'sort_by_appearance' of 'conditional_join' is deprecated.",
              DeprecationWarning,
              stacklevel=find_stack_level(),
          )
      check("sort_by_appearance", sort_by_appearance, [bool])
  
      if (df.columns.nlevels > 1) and (
          isinstance(df_columns, dict)
          or isinstance(right_columns, dict)
      ):
          raise ValueError(
              "Column renaming with a dictionary is not supported "
              "for MultiIndex columns."
          )
  
      check("keep", keep, [str])
  
      if keep not in {"all", "first", "last"}:
          raise ValueError(
              "'keep' should be one of 'all', 'first', 'last'."
          )
  
      check("use_numba", use_numba, [bool])
  
      check("indicator", indicator, [bool, str])
  
      check("force", force, [bool])
  
      return (
          df,
          right,
          conditions,
          how,
          sort_by_appearance,
          df_columns,
          right_columns,
          keep,
          use_numba,
          indicator,
          force,
      )
  
imports: from __future__ import annotations
  import operator
  import warnings
  from typing import Any, Hashable, Literal, Optional, Union
  import numpy
  import pandas
  import pandas_flavor
  from pandas.api.types import is_datetime64_dtype, is_dtype_equal, is_extension_array_dtype, is_numeric_dtype, is_timedelta64_dtype
  from pandas.core.reshape.merge import _MergeOperation
  from janitor.functions.utils import _generic_func_cond_join, _JoinOperator, _keep_output, col, greater_than_join_types, less_than_join_types
  from janitor.utils import check, check_column, find_stack_level
label_desc: Use image node_id 3 for calling a global function with example usage: _conditional_join_preliminary_checks(df, right, conditions, how, sort_by_appearance, df_columns, right_columns, keep, use_numba, indicator, force, return_matching_indices) and returns: df,  right,  conditions,  how,  sort_by_appearance,  df_columns,  right_columns,  keep,  use_numba,  indicator,  force