Repository: quantopian/zipline
File: zipline/pipeline/loaders/blaze/core.py (Python)

Code before:
        return repr(_expr_data_base(
            str(self.expr),
            str(self.deltas),
            str(self.checkpoints),
            dict(self.odo_kwargs),
        ))

    @staticmethod
    def _expr_eq(a, b):
        return a is b is None or a.isidentical(b)

    def __eq__(self, other):
        if not isinstance(other, ExprData):
            return NotImplemented

        return (
            self.expr.isidentical(other.expr) and
            self._expr_eq(self.deltas, other.deltas) and
            self._expr_eq(self.checkpoints, other.checkpoints) and
            self.odo_kwargs == other.odo_kwargs
        )

    def __ne__(self, other):
        return not (self == other)


class BlazeLoader(object):
    """A PipelineLoader for datasets constructed with ``from_blaze``.

    Parameters
    ----------
    dsmap : mapping, optional
        An initial mapping of datasets to ``ExprData`` objects.
        NOTE: Further mutations to this map will not be reflected by this
        object.
    pool : Pool, optional
        The pool to use to run blaze queries concurrently. This object must
        support ``imap_unordered``, ``apply`` and ``apply_async`` methods.

    Attributes
    ----------
    pool : Pool
        The pool to use to run blaze queries concurrently. This object must
        support ``imap_unordered``, ``apply`` and ``apply_async`` methods.
        It is possible to change the pool after the loader has been
        constructed. This allows us to set a new pool for the ``global_loader``
        like: ``global_loader.pool = multiprocessing.Pool(4)``.

    See Also
    --------
    :class:`zipline.utils.pool.SequentialPool`

Review comment (suggestion):
I think this is the default behavior. Is there a reason to implement this explicitly?

```
In [16]: class Foo(object):
    ...:
    ...:     def __eq__(self, other):
    ...:         print("calling eq")
    ...:         return True
    ...:
    ...:

In [17]: Foo() == Foo()
calling eq
Out[17]: True

In [18]: Foo() != Foo()
calling eq
Out[18]: False
```

Code after:
        return repr(_expr_data_base(
            str(self.expr),
            str(self.deltas),
            str(self.checkpoints),
            dict(self.odo_kwargs),
        ))

    @staticmethod
    def _expr_eq(a, b):
        return a is b is None or a.isidentical(b)

    def __hash__(self):
        return super(ExprData, self).__hash__()

    def __eq__(self, other):
        if not isinstance(other, ExprData):
            return NotImplemented

        return (
            self._expr_eq(self.expr, other.expr) and
            self._expr_eq(self.deltas, other.deltas) and
            self._expr_eq(self.checkpoints, other.checkpoints) and
            self.odo_kwargs == other.odo_kwargs
        )

    def __ne__(self, other):
        # note: ``tuple`` (inherited from ``namedtuple``) adds a ``__ne__``,
        # but we want to rely on ``__eq__` to use ``isidentical`` to compare
        # expressions
        return not (self == other)


class BlazeLoader(object):
    """A PipelineLoader for datasets constructed with ``from_blaze``.

    Parameters
    ----------
    dsmap : mapping, optional
        An initial mapping of datasets to ``ExprData`` objects.
        NOTE: Further mutations to this map will not be reflected by this
        object.
    pool : Pool, optional
        The pool to use to run blaze queries concurrently. This object must
        support ``imap_unordered``, ``apply`` and ``apply_async`` methods.

    Attributes
    ----------
    pool : Pool
        The pool to use to run blaze queries concurrently. This object must
        support ``imap_unordered``, ``apply`` and ``apply_async`` methods.
        It is possible to change the pool after the loader has been