code: def conditional_join(
      df: pd.DataFrame,
      right: Union[pd.DataFrame, pd.Series],
      *conditions: Any,
      how: Literal["inner", "left", "right", "outer"] = "inner",
      sort_by_appearance: bool = False,
      df_columns: Optional[Any] = slice(None),
      right_columns: Optional[Any] = slice(None),
      keep: Literal["first", "last", "all"] = "all",
      use_numba: bool = False,
      indicator: Optional[Union[bool, str]] = False,
      force: bool = False,
  ) -> pd.DataFrame:
      """The conditional_join function operates similarly to `pd.merge`,
      but supports joins on inequality operators,
      or a combination of equi and non-equi joins.
  
      Joins solely on equality are not supported.
  
      If the join is solely on equality, `pd.merge` function
      covers that; if you are interested in nearest joins, asof joins,
      or rolling joins, then `pd.merge_asof` covers that.
      There is also pandas' IntervalIndex, which is efficient for range joins,
      especially if the intervals do not overlap.
  
      Column selection in `df_columns` and `right_columns` is possible using the
      [`select`][janitor.functions.select.select] syntax.
  
      Performance might be improved by setting `use_numba` to `True`.
      This assumes that `numba` is installed.
  
      This function returns rows, if any, where values from `df` meet the
      condition(s) for values from `right`. The conditions are passed in
      as a variable argument of tuples, where the tuple is of
      the form `(left_on, right_on, op)`; `left_on` is the column
      label from `df`, `right_on` is the column label from `right`,
      while `op` is the operator.
  
      The `col` class is also supported in the `conditional_join` syntax.
  
      For multiple conditions, the and(`&`)
      operator is used to combine the results of the individual conditions.
  
      In some scenarios there might be performance gains if the less than join,
      or the greater than join condition, or the range condition
      is executed before the equi join - pass `force=True` to force this.
  
      The operator can be any of `==`, `!=`, `<=`, `<`, `>=`, `>`.
  
      The join is done only on the columns.
  
      For non-equi joins, only numeric, timedelta and date columns are supported.
  
      `inner`, `left`, `right` and `outer` joins are supported.
  
      If the columns from `df` and `right` have nothing in common,
      a single index column is returned; else, a MultiIndex column
      is returned.
  
      Examples:
          >>> import pandas as pd
          >>> import janitor
          >>> df1 = pd.DataFrame({"value_1": [2, 5, 7, 1, 3, 4]})
          >>> df2 = pd.DataFrame({"value_2A": [0, 3, 7, 12, 0, 2, 3, 1],
          ...                     "value_2B": [1, 5, 9, 15, 1, 4, 6, 3],
          ...                    })
          >>> df1
             value_1
          0        2
          1        5
          2        7
          3        1
          4        3
          5        4
          >>> df2
             value_2A  value_2B
          0         0         1
          1         3         5
          2         7         9
          3        12        15
          4         0         1
          5         2         4
          6         3         6
          7         1         3
  
          >>> df1.conditional_join(
          ...     df2,
          ...     ("value_1", "value_2A", ">"),
          ...     ("value_1", "value_2B", "<")
          ... )
             value_1  value_2A  value_2B
          0        2         1         3
          1        5         3         6
          2        3         2         4
          3        4         3         5
          4        4         3         6
  
          Use the `col` class:
          >>> df1.conditional_join(
          ...     df2,
          ...     col("value_1") > col("value_2A"),
          ...     col("value_1") < col("value_2B")
          ... )
             value_1  value_2A  value_2B
          0        2         1         3
          1        5         3         6
          2        3         2         4
          3        4         3         5
          4        4         3         6
  
          Select specific columns, after the join:
          >>> df1.conditional_join(
          ...     df2,
          ...     col("value_1") > col("value_2A"),
          ...     col("value_1") < col("value_2B"),
          ...     right_columns='value_2B',
          ...     how='left'
          ... )
             value_1  value_2B
          0        2       3.0
          1        5       6.0
          2        7       NaN
          3        1       NaN
          4        3       4.0
          5        4       5.0
          6        4       6.0
  
          Rename columns, before the join:
          >>> (df1
          ...  .rename(columns={'value_1':'left_column'})
          ...  .conditional_join(
          ...      df2,
          ...      ("left_column", "value_2A", ">"),
          ...      ("left_column", "value_2B", "<"),
          ...      right_columns='value_2B',
          ...      how='outer')
          ... )
              left_column  value_2B
          0           7.0       NaN
          1           1.0       NaN
          2           2.0       3.0
          3           5.0       6.0
          4           3.0       4.0
          5           4.0       5.0
          6           4.0       6.0
          7           NaN       1.0
          8           NaN       9.0
          9           NaN      15.0
          10          NaN       1.0
  
          Get the first match:
          >>> df1.conditional_join(
          ...     df2,
          ...     col("value_1") > col("value_2A"),
          ...     col("value_1") < col("value_2B"),
          ...     keep='first'
          ... )
             value_1  value_2A  value_2B
          0        2         1         3
          1        5         3         6
          2        3         2         4
          3        4         3         5
  
          Get the last match:
          >>> df1.conditional_join(
          ...     df2,
          ...     col("value_1") > col("value_2A"),
          ...     col("value_1") < col("value_2B"),
          ...     keep='last'
          ... )
             value_1  value_2A  value_2B
          0        2         1         3
          1        5         3         6
          2        3         2         4
          3        4         3         6
  
          Add an indicator column:
          >>> df1.conditional_join(
          ...     df2,
          ...     ("value_1", "value_2A", ">"),
          ...     ("value_1", "value_2B", "<"),
          ...     how='outer',
          ...     indicator=True
          ... )
              value_1      _merge  value_2A  value_2B
          0       7.0   left_only       NaN       NaN
          1       1.0   left_only       NaN       NaN
          2       2.0        both       1.0       3.0
          3       5.0        both       3.0       6.0
          4       3.0        both       2.0       4.0
          5       4.0        both       3.0       5.0
          6       4.0        both       3.0       6.0
          7       NaN  right_only       0.0       1.0
          8       NaN  right_only       7.0       9.0
          9       NaN  right_only      12.0      15.0
          10      NaN  right_only       0.0       1.0
  
      !!! abstract "Version Changed"
  
          - 0.24.0
              - Added `df_columns`, `right_columns`, `keep` and `use_numba` parameters.
          - 0.24.1
              - Added `indicator` parameter.
          - 0.25.0
              - `col` class supported.
              - Outer join supported. `sort_by_appearance` deprecated.
              - Numba support for equi join
          - 0.27.0
              - Added support for timedelta dtype.
  
      Args:
          df: A pandas DataFrame.
          right: Named Series or DataFrame to join to.
          conditions: Variable argument of tuple(s) of the form
              `(left_on, right_on, op)`, where `left_on` is the column
              label from `df`, `right_on` is the column label from `right`,
              while `op` is the operator.
              The `col` class is also supported. The operator can be any of
              `==`, `!=`, `<=`, `<`, `>=`, `>`. For multiple conditions,
              the and(`&`) operator is used to combine the results
              of the individual conditions.
          how: Indicates the type of join to be performed.
              It can be one of `inner`, `left`, `right` or `outer`.
          sort_by_appearance: If `how = inner` and
              `sort_by_appearance = False`, there
              is no guarantee that the original order is preserved.
              Usually, this offers more performance.
              If `how = left`, the row order from the left dataframe
              is preserved; if `how = right`, the row order
              from the right dataframe is preserved.
              !!!warning "Deprecated in 0.25.0"
          df_columns: Columns to select from `df` in the final output dataframe.
              Column selection is based on the
              [`select`][janitor.functions.select.select] syntax.
          right_columns: Columns to select from `right` in the final output dataframe.
              Column selection is based on the
              [`select`][janitor.functions.select.select] syntax.
          use_numba: Use numba, if installed, to accelerate the computation.
          keep: Choose whether to return the first match, last match or all matches.
          indicator: If `True`, adds a column to the output DataFrame
              called `_merge` with information on the source of each row.
              The column can be given a different name by providing a string argument.
              The column will have a Categorical type with the value of `left_only`
              for observations whose merge key only appears in the left DataFrame,
              `right_only` for observations whose merge key
              only appears in the right DataFrame, and `both` if the observation’s
              merge key is found in both DataFrames.
          force: If `True`, force the non-equi join conditions to execute before the equi join.
  
  
      Returns:
          A pandas DataFrame of the two merged Pandas objects.
      """  # noqa: E501
  
      return _conditional_join_compute(
          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 1 for calling a global function with example usage: conditional_join(df, right) and returns: _conditional_join_compute