# Path: drain/util.py
# def create_engine():
# def create_db():
# def execute_sql(sql, engine):
# def mtime(path):
# def parse_dates(df, inplace=True, *args, **kwargs):
# def touch(path):
# def get_subdirs(directory):
# def intersect(sets):
# def union(sets):
# def to_float(*args):
# def timestamp(year, month, day):
# def date_to_days(date):
# def date_ceil(month, day):
#     def ceil(t):
# def date_floor(month, day):
#     def floor(t):
# def eqattr(object1, object2, attr):
# def get_attr(name):
# def init_object(name, **kwargs):
# def randtimedelta(low, high, size):
# def randdates(start, end, size):
# def mode(series):
# def get_collinear(df, tol=.1, verbose=False):
# def drop_collinear(df, tol=.1, verbose=True):
# def cross_join(left, right, lsuffix='_left', rsuffix='_right'):
# def dict_merge(*dict_args):
# def dict_subset(d, keys):
# def drop_constant_column_levels(df):
# def list_expand(d, prefix=None):
# def dict_expand(d, prefix=None):
# def nunique(iterable):
# def dict_diff(dicts):
# def make_list(a):
# def make_tuple(a):
# def get_collection_values(a):
# def dict_product(*d, **kwargs):
# def dict_filter_none(d):
# def list_filter_none(l):
# def dict_update_union(d1, d2):
# def set_dtypes(df, dtypes):
# def read_file(filename):
# def conditional_join(left, right, left_on, right_on, condition,
#                      lsuffix='_left', rsuffix='_right'):
#     def to_sql(self, frame, name, if_exists='fail', index=True,
#                index_label=None, schema=None, chunksize=None,
#                dtype=None, pk=None, prefixes=None, raise_on_error=True):
#     def read_table(self, name, schema=None):
#     def read_sql(self, query, raise_on_error=True, **kwargs):
# def indent(s, n_spaces=2, initial=True):
# def is_instance_collection(c, cls):
# class PgSQLDatabase(pandas.io.sql.SQLDatabase):
# 
# Path: drain/step.py
# _STEP_CACHE = {}
#     DEFAULT = 1
# def load(steps, reload=False):
#     def __new__(cls, *args, **kwargs):
#     def __init__(self, inputs=None, dependencies=None, **kwargs):
#     def execute(self, inputs=None, output=None, load_targets=False):
#     def _hasher(self):
#     def _digest(self):
#     def get_input(self, value, _search=None):
#     def get_inputs(self, _visited=None):
#     def get_arguments(self, **include):
#     def _output_dirname(self):
#     def _yaml_filename(self):
#     def _dump_dirname(self):
#     def _target_filename(self):
#     def run(self):
#     def load(self):
#     def setup_dump(self):
#     def dump(self):
#     def __repr__(self):
#     def __hash__(self):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __init__(self, args=None, kwargs=None):
# def _simplify_arguments(arguments):
# def merge_results(inputs, arguments=None):
#     def __init__(self, step, key=None):
#     def run(self, *args, **kwargs):
#     def __init__(self, inputs, mapping):
#     def run(self, *args, **kwargs):
#     def __init__(self, _base, _method_name=None, inputs=None, **kwargs):
#     def run(self, *args, **update_kwargs):
# def _expand_inputs(step, steps=None):
# def _collect_kwargs(step, drop_duplicate_names=True):
# def _output_dirnames(workflow=None, leaf=False):
# class Step(object):
# class Arguments(object):
# class GetItem(Step):
# class MapResults(Step):
# class Call(Step):


from tempfile import NamedTemporaryFile
from pprint import pformat
from itertools import product
from sklearn import tree
from collections import Counter
from six import StringIO
from drain import util, step
import pandas as pd
    import wand.image
    import pydot
        df.index = expanded.index

    else:
        df = pd.concat((expanded, self), axis=1)
        # When index=False, the index is still a Step collection
        df = StepFrame(expanded)

    return df


def dapply(self, fn, pairwise=False, symmetric=True, diagonal=False, block=None, **kwargs):
    """
    Apply function to each step object in the index

    Args:
        fn: function to apply. If a list then each function is applied
        pairwise: whether to apply the function to pairs of steps
        symmetric, diagonal, block: passed to apply_pairwise when pairwise=True
        kwargs: a keyword arguments to pass to each function. Arguments
            with list value are grid searched using util.dict_product.

    Returns: a StepFrame or StepSeries
    """
    search_keys = [k for k, v in kwargs.items() if isinstance(v, list) and len(v) > 1]
    functions = util.make_list(fn)
    search = list(product(functions, util.dict_product(kwargs)))

    results = []
    for fn, kw in search:
        if not pairwise:

# Path: drain/util.py
# def create_engine():
# def create_db():
# def execute_sql(sql, engine):
# def mtime(path):
# def parse_dates(df, inplace=True, *args, **kwargs):
# def touch(path):
# def get_subdirs(directory):
# def intersect(sets):
# def union(sets):
# def to_float(*args):
# def timestamp(year, month, day):
# def date_to_days(date):
# def date_ceil(month, day):
#     def ceil(t):
# def date_floor(month, day):
#     def floor(t):
# def eqattr(object1, object2, attr):
# def get_attr(name):
# def init_object(name, **kwargs):
# def randtimedelta(low, high, size):
# def randdates(start, end, size):
# def mode(series):
# def get_collinear(df, tol=.1, verbose=False):
# def drop_collinear(df, tol=.1, verbose=True):
# def cross_join(left, right, lsuffix='_left', rsuffix='_right'):
# def dict_merge(*dict_args):
# def dict_subset(d, keys):
# def drop_constant_column_levels(df):
# def list_expand(d, prefix=None):
# def dict_expand(d, prefix=None):
# def nunique(iterable):
# def dict_diff(dicts):
# def make_list(a):
# def make_tuple(a):
# def get_collection_values(a):
# def dict_product(*d, **kwargs):
# def dict_filter_none(d):
# def list_filter_none(l):
# def dict_update_union(d1, d2):
# def set_dtypes(df, dtypes):
# def read_file(filename):
# def conditional_join(left, right, left_on, right_on, condition,
#                      lsuffix='_left', rsuffix='_right'):
#     def to_sql(self, frame, name, if_exists='fail', index=True,
#                index_label=None, schema=None, chunksize=None,
#                dtype=None, pk=None, prefixes=None, raise_on_error=True):
#     def read_table(self, name, schema=None):
#     def read_sql(self, query, raise_on_error=True, **kwargs):
# def indent(s, n_spaces=2, initial=True):
# def is_instance_collection(c, cls):
# class PgSQLDatabase(pandas.io.sql.SQLDatabase):
# 
# Path: drain/step.py
# _STEP_CACHE = {}
#     DEFAULT = 1
# def load(steps, reload=False):
#     def __new__(cls, *args, **kwargs):
#     def __init__(self, inputs=None, dependencies=None, **kwargs):
#     def execute(self, inputs=None, output=None, load_targets=False):
#     def _hasher(self):
#     def _digest(self):
#     def get_input(self, value, _search=None):
#     def get_inputs(self, _visited=None):
#     def get_arguments(self, **include):
#     def _output_dirname(self):
#     def _yaml_filename(self):
#     def _dump_dirname(self):
#     def _target_filename(self):
#     def run(self):
#     def load(self):
#     def setup_dump(self):
#     def dump(self):
#     def __repr__(self):
#     def __hash__(self):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __init__(self, args=None, kwargs=None):
# def _simplify_arguments(arguments):
# def merge_results(inputs, arguments=None):
#     def __init__(self, step, key=None):
#     def run(self, *args, **kwargs):
#     def __init__(self, inputs, mapping):
#     def run(self, *args, **kwargs):
#     def __init__(self, _base, _method_name=None, inputs=None, **kwargs):
#     def run(self, *args, **update_kwargs):
# def _expand_inputs(step, steps=None):
# def _collect_kwargs(step, drop_duplicate_names=True):
# def _output_dirnames(workflow=None, leaf=False):
# class Step(object):
# class Arguments(object):
# class GetItem(Step):
# class MapResults(Step):
# class Call(Step):


# Path: drain/exploration.py
from tempfile import NamedTemporaryFile
from pprint import pformat
from itertools import product
from sklearn import tree
from collections import Counter
from six import StringIO
from drain import util, step
import pandas as pd
    import wand.image
    import pydot

        df.index = expanded.index

    else:
        df = pd.concat((expanded, self), axis=1)
        # When index=False, the index is still a Step collection
        df = StepFrame(expanded)

    return df


def dapply(self, fn, pairwise=False, symmetric=True, diagonal=False, block=None, **kwargs):
    """
    Apply function to each step object in the index

    Args:
        fn: function to apply. If a list then each function is applied
        pairwise: whether to apply the function to pairs of steps
        symmetric, diagonal, block: passed to apply_pairwise when pairwise=True
        kwargs: a keyword arguments to pass to each function. Arguments
            with list value are grid searched using util.dict_product.

    Returns: a StepFrame or StepSeries
    """
    search_keys = [k for k, v in kwargs.items() if isinstance(v, list) and len(v) > 1]
    functions = util.make_list(fn)
    search = list(product(functions, util.dict_product(kwargs)))

    results = []
    for fn, kw in search:
        if not pairwise:

            r = self.index.to_series().apply(lambda step: fn(step, **kw))