Code Along for New Project

Step 1: Project Setup and Version Control Initialization

In this step, we create the project directory, initialize a Git repository, and set up a Python virtual environment. This will ensure that dependencies are isolated and version control is ready for tracking changes. Run the following commands in your terminal:


Create project directory and enter it

mkdir StockPriceNotifier cd StockPriceNotifier

Initialize a Git repository

git init

Set up a virtual environment (using Python 3)

python3 -m venv env source env/bin/activate # On Windows, run: env\Scripts\activate

Create the directory structure and necessary files

mkdir src tests touch src/init.py touch README.md requirements.txt

Explanation: • The virtual environment (env) ensures that your dependencies don’t conflict with the system libraries. • The src folder will contain our application code, while tests will host our unit tests. • Git is initialized to help you maintain version control over the project files.


Step 2: Design the Stock Data Model with OOP

We define a Stock class that will encapsulate the data and behaviors related to a stock, such as the symbol and price. In this improved version, we add type hints, docstrings, and enhanced logging support, which is very useful during debugging.

File: src/stock.py

#!/usr/bin/env python3 “”" Module: stock.py This module defines the Stock class for maintaining stock information. “”"

class Stock: def init(self, symbol: str, price: float) → None: “”" Initialize the Stock with a symbol and an initial price. :param symbol: The stock ticker symbol (e.g., ‘AAPL’). :param price: Initial price of the stock. “”" self.symbol = symbol self.price = price

def update_price(self, new_price: float) -> float:
    """
    Update the stock price and compute the change.
    :param new_price: The updated stock price.
    :return: The difference between the new and the old price.
    """
    change = new_price - self.price
    self.price = new_price
    return change

def __str__(self) -> str:
    """Return a string representation of the stock."""
    return f"Stock(symbol={self.symbol}, price={self.price})"

if name == “main”: # Simple demonstration for debugging purposes apple = Stock(“AAPL”, 150.0) print(“Initial state:”, apple) change = apple.update_price(155.0) print(“After update:”, apple) print(“Price change:”, change)

Explanation: • The Stock class models a stock with a symbol and a price. • The update_price method calculates how much the price changed and then updates the price attribute. • Type hints and docstrings have been added to improve code readability and maintenance.


Step 3: Implement the Notification System

We now design a Notifier class that will monitor stock price changes and notify the user when the change exceeds a certain threshold. In a production system, this could be expanded to send emails, SMS, etc. For now, we’ll simply print alerts to the console.

File: src/notifier.py

#!/usr/bin/env python3 “”" Module: notifier.py This module defines the Notifier class which triggers alerts when stock price changes exceed a threshold. “”"

class Notifier: def init(self, threshold: float) → None: “”" Initialize with a threshold value for alert notifications. :param threshold: Minimum absolute change required to trigger an alert. “”" self.threshold = threshold

def check_and_notify(self, stock, change: float) -> None:
    """
    Check the stock price change and send notification if it exceeds the threshold.
    :param stock: The Stock instance.
    :param change: The price change computed.
    """
    if abs(change) >= self.threshold:
        self.notify(stock, change)

def notify(self, stock, change: float) -> None:
    """
    Send a notification. Here we use print, but this can be replaced with more complex logic.
    :param stock: The Stock instance.
    :param change: The price change.
    """
    direction = "increased" if change > 0 else "decreased"
    message = (f"Alert: {stock.symbol} has {direction} by {abs(change)} "
               f"to {stock.price}!")
    print(message)

if name == “main”: # Direct testing of the notifier functionality from stock import Stock apple = Stock(“AAPL”, 150.0) notifier = Notifier(threshold=4) price_change = apple.update_price(156.0) notifier.check_and_notify(apple, price_change)

Explanation: • Notifier is initialized with a threshold value used to determine whether or not to alert. • The check_and_notify method calculates whether the absolute change meets or exceeds the threshold and then calls notify. • The notify method outputs a simple message; you can replace this with any actual notification mechanism you prefer.


Step 4: Simulate Real-Time Data Fetching

In this step, we simulate real-time data by periodically updating the stock price with random fluctuations. This code uses Python’s time.sleep to mimic real-time delays.

File: src/simulator.py

#!/usr/bin/env python3 “”" Module: simulator.py Simulates real-time stock price updates by generating random fluctuations. “”"

import random import time from stock import Stock from notifier import Notifier

class StockSimulator: def init(self, stock: Stock, notifier: Notifier, interval: int = 2, iterations: int = 5) → None: “”" Initialize the simulator for a given stock and notifier. :param stock: Stock instance to simulate. :param notifier: Notifier instance to alert on significant price changes. :param interval: Time interval between updates in seconds. :param iterations: Number of simulated price updates. “”" self.stock = stock self.notifier = notifier self.interval = interval self.iterations = iterations

def simulate(self) -> None:
    """Run the simulation of price updates."""
    print(f"Starting simulation for {self.stock.symbol}...")
    for i in range(self.iterations):
        # Simulate a random price change between -5 and +5
        new_price = round(self.stock.price + random.uniform(-5, 5), 2)
        change = self.stock.update_price(new_price)
        print(f"[Iteration {i+1}] Updated {self.stock.symbol} to {self.stock.price}")
        self.notifier.check_and_notify(self.stock, change)
        time.sleep(self.interval)
    print("Simulation complete.")

if name == “main”: apple = Stock(“AAPL”, 150.0) notifier = Notifier(threshold=3) simulator = StockSimulator(apple, notifier, interval=2, iterations=10) simulator.simulate()

Explanation: • StockSimulator takes a Stock instance and a Notifier, simulating price updates at fixed intervals. • Each iteration generates a new random price, applies the update, and checks if a notification is needed. • Interval and iteration count are parameterized so that you can easily adjust the simulation timing and duration.


Step 5: Debugging and Unit Testing

Now we write unit tests to ensure that the functionality of our Stock and Notifier classes is as expected. We use Python’s built-in unittest framework for this. The tests include both price update validations and notifications trigger conditions.

File: tests/test_stock.py

#!/usr/bin/env python3 “”" Unit tests for the Stock class. “”"

import unittest from src.stock import Stock

class TestStock(unittest.TestCase): def setUp(self) → None: self.stock = Stock(“GOOGL”, 2000.0)

def test_update_price_increase(self) -> None:
    change = self.stock.update_price(2005.0)
    self.assertEqual(change, 5.0)
    self.assertEqual(self.stock.price, 2005.0, "Price should be updated to 2005.0")

def test_update_price_decrease(self) -> None:
    change = self.stock.update_price(1995.0)
    self.assertEqual(change, -5.0)
    self.assertEqual(self.stock.price, 1995.0, "Price should be updated to 1995.0")

if name == ‘main’: unittest.main()

File: tests/test_notifier.py

#!/usr/bin/env python3 “”" Unit tests for the Notifier class. “”"

import unittest from src.stock import Stock from src.notifier import Notifier

class TestNotifier(unittest.TestCase): def setUp(self) → None: self.stock = Stock(“TSLA”, 600.0) self.threshold = 10.0 # We capture notifications by overriding the notify method for testing. self.notifications =

    class TestNotifierClass(Notifier):
        def notify(inner_self, stock, change: float) -> None:
            """Override notify to capture the notification message."""
            direction = "increased" if change > 0 else "decreased"
            message = f"{stock.symbol} {direction} by {abs(change)} to {stock.price}"
            self.notifications.append(message)

    self.notifier = TestNotifierClass(threshold=self.threshold)

def test_notification_trigger(self) -> None:
    # Price increase that exceeds the threshold (e.g., change of 15)
    change = self.stock.update_price(615.0)
    self.notifier.check_and_notify(self.stock, change)
    self.assertTrue(len(self.notifications) > 0, "A notification should have been triggered.")

def test_no_notification(self) -> None:
    # Price change that does not exceed the threshold (e.g., change of 5)
    change = self.stock.update_price(605.0)
    self.notifier.check_and_notify(self.stock, change)
    self.assertEqual(len(self.notifications), 0, "No notification should be triggered for small changes.")

if name == ‘main’: unittest.main()

Explanation: • The test_stock.py file checks that the Stock class correctly updates its price and calculates the change. • The test_notifier.py file uses a subclass of Notifier (TestNotifierClass) to override notify – this way, we capture the notification messages instead of printing them. This makes it easier to assert whether notifications were sent. • Running these tests helps ensure our classes work correctly before integrating them into the simulator.


Step 6: Final Integration and Commit

After confirming that your code works fine with the unit tests, integrate all modules by running the simulation, perform final debugging, and commit your code using Git.

In your terminal, execute the following commands:


Run unit tests from the tests directory to ensure everything is working correctly

python -m unittest discover -s tests

Once tests pass, add all files to Git

git add .

Commit with an informative message summarizing your work

git commit -m “Initial commit: Added stock model, notifier, simulator, and unit tests for real-time stock price notifier”

Explanation: • Running the tests ensures that any new code meets the defined requirements immediately. • Using Git for commit management helps in tracking changes, and provides the ability to roll back if necessary.


Congratulations!

You’ve now built a comprehensive, real-time stock price notifier using Python. This project demonstrates effective object-oriented design, simulates real-time data fetching, includes a notification mechanism, and employs debugging and testing practices. As you further develop this project, consider integrating real APIs or asynchronous processing (asyncio) for more realistic data handling. Happy coding!