code: def __call__(self, lhs: TileableType, rhs: TileableType):
      if self.broadcast_axis != 1 or lhs.ndim == rhs.ndim:
          self._output_types = get_output_types(lhs, rhs)
      else:
          self._output_types = [
              OutputType.dataframe,
              OutputType.dataframe,
          ]
  
      if lhs.ndim == rhs.ndim:
          if lhs.ndim == 1:
              return self._call_series_series(lhs, rhs)
          else:
              return self._call_dataframe_dataframe(lhs, rhs)
      else:
          if lhs.ndim == 1:
              # join order need to be reversed if not symmetric
              asym_joins = {"left", "right"} - {self.join}
              if len(asym_joins) == 1:  # self.join in {"left", "right"}
                  self.join = asym_joins.pop()
              # need to put dataframe first
              self._output_types = get_output_types(rhs, lhs)
              return self._call_dataframe_series(rhs, lhs)[::-1]
          else:
              return self._call_dataframe_series(lhs, rhs)
  
imports: from typing import Any, Optional, Union
  import numpy
  from ...None import opcodes
  from ...core import get_output_types, recursive_tile, OutputType
  from ...serialization.serializables import AnyField, KeyField, StringField, Int16Field, Int64Field
  from ...typing import TileableType
  from ..operands import DataFrameOperand, DataFrameOperandMixin
  from ..align import align_dataframe_dataframe, align_dataframe_series, align_series_series
  from ..core import IndexValue
  from ..utils import validate_axis, parse_index, build_empty_df
label_desc: Use image node_id 3 for calling the DataFrameAlign obj's underlying member method code with example usage: obj.__call__(lhs, rhs) and returns: self, self, self, self