Repository: quantopian/zipline
File: zipline/algorithm.py (Python)

Code before:
            self.initialized = True

        benchmark_source = self._create_benchmark_source()

        self.trading_client = AlgorithmSimulator(
            self,
            sim_params,
            self.data_portal,
            self._create_clock(),
            benchmark_source,
            self.restrictions,
            universe_func=self._calculate_universe
        )

        metrics_tracker.handle_start_of_simulation(benchmark_source)
        return self.trading_client.transform()

    def _calculate_universe(self):
        # this exists to provide backwards compatibility for older,
        # deprecated APIs, particularly around the iterability of
        # BarData (ie, 'for sid in data`).

        # our universe is all the assets passed into `run`.
        return self._assets_from_source

    def _compute_pipelines(self):
        for name, p in self._pipelines.items():
            if p[2]:
                self.pipeline_output(name)

    def get_generator(self):
        """
        Override this method to add new logic to the construction
        of the generator. Overrides can use the _create_generator
        method to get a standard construction generator.
        """
        return self._create_generator(self.sim_params)

    def run(self, data=None, overwrite_sim_params=True):
        """Run the algorithm.

        :Arguments:
            source : DataPortal

        :Returns:
            daily_stats : pandas.DataFrame
              Daily performance metrics such as returns, alpha etc.

        """
        # XXX: _assets_from_source is a backwards compatibility shim for old,
        #      deprecated APIs that treat BarData like a dictionary with asset

Review comment (suggestion):
Couple notes on this method:

1. Since we intend to override this to be called in a subclass downstream, we should make this a public method and document it. 
2. I would probably name this something like `compute_eager_pipelines` to make it clearer that this only computes pipelines that were attached with `eager=True`.
3. It doesn't look like anything is actually calling this in Zipline right now. I would expect that we want to call this at the start of `TradingAlgorithm.before_trading_start`. Note that that function exits early if `self._before_trading_start` is None, but we should still run eager pipelines even if the user hasn't defined a BTS, since part of the purpose of this PR is to remove the need for superfluous BTS implementations that just call pipeline_output and copy results onto context. 
4. We need a test for the new behavior here. Testing this is a bit tricky, since the values exposed to the user shouldn't change; only when they get computed. One way to test that things are computed in the correct order would be to create an algorithm that logs in its `before_trading_start` and during the execution of a `CustomFactor`. You can then capture the logs using a logbook TestHandler and verify that the logs from the CustomFactor fire before the logs from before_trading_start. (You could also do something similar by appending to a list on context instead of logging).

Code after:
        if sim_params is not None:
            self.sim_params = sim_params

        self.metrics_tracker = metrics_tracker = self._create_metrics_tracker()

        # Set the dt initially to the period start by forcing it to change.
        self.on_dt_changed(self.sim_params.start_session)

        if not self.initialized:
            self.initialize(*self.initialize_args, **self.initialize_kwargs)
            self.initialized = True

        benchmark_source = self._create_benchmark_source()

        self.trading_client = AlgorithmSimulator(
            self,
            sim_params,
            self.data_portal,
            self._create_clock(),
            benchmark_source,
            self.restrictions,
            universe_func=self._calculate_universe
        )

        metrics_tracker.handle_start_of_simulation(benchmark_source)
        return self.trading_client.transform()

    def _calculate_universe(self):
        # this exists to provide backwards compatibility for older,
        # deprecated APIs, particularly around the iterability of
        # BarData (ie, 'for sid in data`).

        # our universe is all the assets passed into `run`.
        return self._assets_from_source

    def compute_eager_pipelines(self):
        """
        Compute any pipelines attached with eager=True.
        """
        for name, pipe in self._pipelines.items():
            if pipe.eager:
                self.pipeline_output(name)

    def get_generator(self):
        """
        Override this method to add new logic to the construction
        of the generator. Overrides can use the _create_generator
        method to get a standard construction generator.
        """
        return self._create_generator(self.sim_params)