This project has been created as part of the 42 curriculum by pabdalla
Replace with necessary values
python3 {exercise.py}
# or directly if the shebang is set:
./{exercise.py}flake8 # style linter
mypy ./ # type checkerThis project teaches object-oriented programming in Python through a series of progressive exercises set in a cyberpunk data processing system. Starting from abstract class design and advancing through polymorphic stream routing, duck typing, and plugin-based export pipelines, each exercise builds directly on the previous one, forming a complete data processing pipeline by the end.
- Defining abstract classes with
ABCand@abstractmethodfrom theabcmodule - Implementing method overriding in specialized subclasses
- Applying subtype polymorphism to route data without knowing concrete types
- Using
typing.Anyfor flexible method signatures while enforcing type safety internally - Returning structured results as
tuple[int, str]from shared interface methods - Implementing duck typing via
typing.Protocolfor export plugin compatibility - Handling invalid data with custom exceptions raised on bad ingestion
- Using
typing.IOand comprehensive type annotations verified withmypy - Adhering to
flake8coding standards throughout
from abc import ABC, abstractmethod— base tools for defining abstract interfaces- A class inheriting from
ABCcannot be instantiated directly - Methods decorated with
@abstractmethodmust be overridden in every concrete subclass - Abstract classes define what subclasses must do, not how — enforcing a shared contract
- Subclasses override abstract methods with their own specific implementations
- Polymorphism allows code to call the same method (
validate,ingest,output) on different objects and get type-appropriate behavior - The caller doesn't need to know the concrete type — only the shared interface matters
Protocol(fromtyping) defines a structural interface without requiring inheritance- Any class that implements the required methods is automatically compatible — no explicit subclassing needed
- This enables a flexible plugin system where export classes are interchangeable
- Each processor maintains an internal ordered store of ingested data
output(self) -> tuple[int, str]extracts the oldest item along with its processing rank (index)- The item is removed from the processor upon extraction — behaves like a queue
- If
ingestis called with invalid data (without priorvalidate), an exception must be raised - This protects data streams from silent corruption
- Deliberately passing wrong types to
ingestwill trigger amypywarning — this is intentional per the subject
| Exercise | File | Concepts |
|---|---|---|
| 0 | ex0/data_processor.py |
ABC, @abstractmethod, method overriding, internal queue, output as tuple |
| 1 | ex1/data_stream.py |
Polymorphic stream routing, processor registration, stream statistics |
| 2 | ex2/data_pipeline.py |
Protocol, duck typing, CSV/JSON export plugins, output_pipeline |