An Overridable Hook

Step 4: An Overridable Hook

Template methods often expose a hook: an optional step with a do-nothing default that subclasses may override to customize the outcome. The skeleton calls it, but subclasses that do not care simply inherit the no-op.

The base Pipeline now defines after_load(result), which returns result unchanged, and run() already calls it as its final step: extract, transform, load, then after_load. Because the default is a no-op, every pipeline from the earlier steps behaves exactly as before.

Implement WrapPipeline, a subclass that overrides after_load(result) to wrap the loaded result in a dict of the form with keys "result" (the loaded list) and "count" (its length). WrapPipeline inherits run() and every step except this one, the hook alone changes the final output.

Hints
Starter code
class Pipeline:
    def __init__(self, source):
        self.source = source

    def extract(self):
        return list(self.source)

    def transform(self, data):
        return data

    def load(self, data):
        return data

    def after_load(self, result):
        return result

    def run(self):
        data = self.extract()
        data = self.transform(data)
        result = self.load(data)
        result = self.after_load(result)
        return result


class UpperPipeline(Pipeline):
    def transform(self, data):
        return [s.upper() for s in data]


class SumPipeline(Pipeline):
    def transform(self, data):
        return [sum(data)]


class WrapPipeline(Pipeline):
    def after_load(self, result):
        """Wrap the loaded result in a dict with its element count (overrides the no-op hook)."""
        # TODO: return {"result": result, "count": len(result)}
        pass
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.