# Buggy code
def fit(self, dataset: Dataset):
    """Calculates statistics for this workflow on the input dataset

    Parameters
    -----------
    dataset: Dataset
        The input dataset to calculate statistics for. If there is a train/test split this
        data should be the training dataset only.
    """
    self._clear_worker_cache()
    ddf = dataset.to_ddf(columns=self._input_columns())

    # Get a dictionary mapping all StatOperators we need to fit to a set of any dependant
    # StatOperators (having StatOperators that depend on the output of other StatOperators
    # means that will have multiple phases in the fit cycle here)
    stat_ops = {
        op: _get_stat_ops(op.parents) for op in _get_stat_ops([self.column_group])
    }

    while stat_ops:
        # get all the StatOperators that we can currently call fit on (no outstanding
        # dependencies)
        current_phase = [
            op for op, dependencies in stat_ops.items() if not dependencies
        ]
        if not current_phase:
            # this shouldn't happen, but lets not infinite loop just in case
            raise RuntimeError("failed to find dependency-free StatOperator to fit")

        stats, ops = [], []
        for column_group in current_phase:
            # apply transforms necessary for the inputs to the current column group, ignoring
            # the transforms from the statop itself
            transformed_ddf = _transform_ddf(ddf, column_group.parents)

            op = column_group.op
            try:
                stats.append(op.fit(column_group.input_column_names, transformed_ddf))
                ops.append(op)
            except Exception:
                LOG.exception("Failed to fit operator %s", column_group.op)
                raise

        if self.client:
            results = [r.result() for r in self.client.compute(stats)]
        else:
            results = dask.compute(stats, scheduler="synchronous")[0]

        for computed_stats, op in zip(results, ops):
            op.fit_finalize(computed_stats)

        # Remove all the operators we processed in this phase, and remove
        # from the dependencies of other ops too
        for stat_op in current_phase:
            stat_ops.pop(stat_op)
        for dependencies in stat_ops.values():
            dependencies.difference_update(current_phase)

    # hack: store input/output dtypes here. We should have complete dtype
    # information for each operator (like we do for column names), but as
    # an interim solution this gets us what we need.
    input_dtypes = dataset.to_ddf().dtypes
    self.input_dtypes = dict(zip(input_dtypes.index, input_dtypes))
    output_dtypes = self.transform(dataset).to_ddf().head(1).dtypes
    self.output_dtypes = dict(zip(output_dtypes.index, output_dtypes))


# Traceback (TypeError)
E0224 15:58:10.330248 178 model_repository_manager.cc:963] failed to load 'amazonreview_tf' version 1: Internal: unable to create stream: the provided PTX was compiled with an unsupported toolchain.
/nvtabular/nvtabular/workflow.py:236: UserWarning: Loading workflow generated with cudf version 0+untagged.1.gbd321d1 - but we are running cudf 0.18.0a+253.g53ed28e91c. This might cause issues
warnings.warn(
E0224 15:58:20.534884 178 model_repository_manager.cc:963] failed to load 'amazonreview_nvt' version 1: Internal: Traceback (most recent call last):
File "/opt/tritonserver/backends/python/startup.py", line 197, in Init
self.backend.initialize(args)
File "/models/models/amazonreview_nvt/1/model.py", line 57, in initialize
self.output_dtypes[name] = triton_string_to_numpy(conf["data_type"])
TypeError: 'NoneType' object is not subscriptable
I0224 15:58:20.535093 178 server.cc:490]

# Fixed code
def fit(self, dataset: Dataset):
    """Calculates statistics for this workflow on the input dataset

    Parameters
    -----------
    dataset: Dataset
        The input dataset to calculate statistics for. If there is a train/test split this
        data should be the training dataset only.
    """
    self._clear_worker_cache()
    ddf = dataset.to_ddf(columns=self._input_columns())

    # Get a dictionary mapping all StatOperators we need to fit to a set of any dependant
    # StatOperators (having StatOperators that depend on the output of other StatOperators
    # means that will have multiple phases in the fit cycle here)
    stat_ops = {
        op: _get_stat_ops(op.parents) for op in _get_stat_ops([self.column_group])
    }

    while stat_ops:
        # get all the StatOperators that we can currently call fit on (no outstanding
        # dependencies)
        current_phase = [
            op for op, dependencies in stat_ops.items() if not dependencies
        ]
        if not current_phase:
            # this shouldn't happen, but lets not infinite loop just in case
            raise RuntimeError("failed to find dependency-free StatOperator to fit")

        stats, ops = [], []
        for column_group in current_phase:
            # apply transforms necessary for the inputs to the current column group, ignoring
            # the transforms from the statop itself
            transformed_ddf = _transform_ddf(ddf, column_group.parents)

            op = column_group.op
            try:
                stats.append(op.fit(column_group.input_column_names, transformed_ddf))
                ops.append(op)
            except Exception:
                LOG.exception("Failed to fit operator %s", column_group.op)
                raise

        if self.client:
            results = [r.result() for r in self.client.compute(stats)]
        else:
            results = dask.compute(stats, scheduler="synchronous")[0]

        for computed_stats, op in zip(results, ops):
            op.fit_finalize(computed_stats)

        # Remove all the operators we processed in this phase, and remove
        # from the dependencies of other ops too
        for stat_op in current_phase:
            stat_ops.pop(stat_op)
        for dependencies in stat_ops.values():
            dependencies.difference_update(current_phase)

    # hack: store input/output dtypes here. We should have complete dtype
    # information for each operator (like we do for column names), but as
    # an interim solution this gets us what we need.
    input_dtypes = dataset.to_ddf()[self._input_columns()].dtypes
    self.input_dtypes = dict(zip(input_dtypes.index, input_dtypes))
    output_dtypes = self.transform(dataset).to_ddf().head(1).dtypes
    self.output_dtypes = dict(zip(output_dtypes.index, output_dtypes))