{"id":30179745,"url":"https://github.com/oleksandr-romashko/goit-pythonweb-hw-01","last_synced_at":"2025-08-12T06:21:07.103Z","repository":{"id":297480402,"uuid":"996864907","full_name":"oleksandr-romashko/goit-pythonweb-hw-01","owner":"oleksandr-romashko","description":"Design patterns, SOLID principles and logging.","archived":false,"fork":false,"pushed_at":"2025-06-05T17:27:27.000Z","size":13,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-05T18:25:33.809Z","etag":null,"topics":["black-formatter","design-patterns","goit-pythonweb-hw-01","logging","python","solid"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oleksandr-romashko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-05T15:23:35.000Z","updated_at":"2025-06-05T17:34:13.000Z","dependencies_parsed_at":"2025-06-05T18:36:06.510Z","dependency_job_id":null,"html_url":"https://github.com/oleksandr-romashko/goit-pythonweb-hw-01","commit_stats":null,"previous_names":["oleksandr-romashko/goit-pythonweb-hw-01"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/oleksandr-romashko/goit-pythonweb-hw-01","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oleksandr-romashko%2Fgoit-pythonweb-hw-01","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oleksandr-romashko%2Fgoit-pythonweb-hw-01/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oleksandr-romashko%2Fgoit-pythonweb-hw-01/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oleksandr-romashko%2Fgoit-pythonweb-hw-01/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oleksandr-romashko","download_url":"https://codeload.github.com/oleksandr-romashko/goit-pythonweb-hw-01/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oleksandr-romashko%2Fgoit-pythonweb-hw-01/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270011288,"owners_count":24511921,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["black-formatter","design-patterns","goit-pythonweb-hw-01","logging","python","solid"],"created_at":"2025-08-12T06:21:05.514Z","updated_at":"2025-08-12T06:21:07.088Z","avatar_url":"https://github.com/oleksandr-romashko.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fullstack Web Development with Python \u003c!-- omit in toc --\u003e\n\n### [# goit-pythonweb-hw-01](https://github.com/topics/goit-pythonweb-hw-01) \u003c!-- omit in toc --\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg align=\"center\" src=\"./assets/thumbnail.svg\" width=\"200\" title=\"Project thumbnail\" alt=\"project thumbnail\"\u003e\n\u003c/p\u003e\n\n\n## Design patterns, SOLID principles, logging, code formatting using black \u003c!-- omit in toc --\u003e\n\nThis work consists of two tasks focused on applying key programming principles in Python.\n\n1. **Task 1 – Factory Pattern:**\n    Refactor a basic vehicle creation system using the Factory design pattern. The goal is to support region-specific specifications (e.g., US Spec, EU Spec) without modifying the core vehicle classes.\n2. **Task 2 – SOLID Principles:**\n    Redesign a simple command-line library management program to follow SOLID principles. The task involves introducing appropriate abstractions and interfaces to make the system more modular, extensible, and maintainable.\n\n\n### Table of Contents \u003c!-- omit in toc --\u003e\n- [Project Setup \\\u0026 Run Instructions](#project-setup--run-instructions)\n  - [Prerequisites](#prerequisites)\n  - [Setting Up the Development Environment](#setting-up-the-development-environment)\n  - [Running the Code](#running-the-code)\n  - [VS Code Debugging (Optional)](#vs-code-debugging-optional)\n- [Task requirements](#task-requirements)\n  - [Task 1: Factory Pattern](#task-1-factory-pattern)\n    - [Task description](#task-description)\n    - [Steps for Task 1](#steps-for-task-1)\n    - [Expected Result](#expected-result)\n  - [Task 2: SOLID Principles](#task-2-solid-principles)\n    - [Task description](#task-description-1)\n    - [Steps for Task 2](#steps-for-task-2)\n- [Task Solution](#task-solution)\n    - [Task 1 solution](#task-1-solution)\n    - [Task 2 solution](#task-2-solution)\n\n### Project Setup \u0026 Run Instructions\n\nThis guide will help you set up the development environment and run tasks from the project.\n\n#### Prerequisites\n\nBefore starting, ensure that you have the following installed:\n\n* **[Python 3.10+](https://www.python.org/downloads/)** (tested with 3.12.3)\n* **[Poetry](https://python-poetry.org/docs/#installation)**\n* (Optional) Git for cloning the repo\n* (Optional) VS Code with the Python and Black extension\n\n#### Setting Up the Development Environment\n\n1. **Clone the Repository**\n\n    If you haven't cloned the project yet, you can do so using:\n\n    ```bash\n    git clone https://github.com/oleksandr-romashko/goit-pythonweb-hw-01.git\n    cd goit-pythonweb-hw-01\n    ```\n\n    or download the ZIP archive from [GitHub Repository](https://github.com/oleksandr-romashko/goit-pythonweb-hw-01) and extract it.\n\n2. **Install Dependencies**\n\n    ```bash\n    poetry install\n    ```\n\n3. **Install Git Hooks with Pre-commit**\n\n    Run this to enable automatic formatting and checks on each commit:\n\n    ```bash\n    poetry run pre-commit install\n    ```\n\n    This enables checks like:\n    * Auto-formatting with **Black**\n    * Docstring-first enforcement\n    * Trailing whitespace \u0026 EOL fixer\n\n\n#### Running the Code\n\n**Task 1 (Factory Pattern)**\n\n```bash\npoetry run python src/goit_pythonweb_hw_01/task_1/main.py\n```\n\n**Task 2 (SOLID Principles)**\n\n```bash\npoetry run python src/goit_pythonweb_hw_01/task_2/main.py\n```\n\n#### VS Code Debugging (Optional)\n\nVS Code debug configurations are preconfigured in the [.vscode/](./.vscode/) directory. If you use VS Code, open the project and choose the appropriate task to run (`Run task 1` or `Run task 2`) from the debug panel.\n\nYou can customize these further as needed.\n\n\n### Task requirements\n\nBoth tasks require:\n\n* The use of **type hints** for type safety.\n* **INFO-level logging** instead of print statements.\n* Code formatting with **Black**.\n\n\n#### Task 1: Factory Pattern\n\n##### Task description\n\nThe following code demonstrates a simple system for creating vehicles. We have two classes: `Car` and `Motorcycle`. Each class has a `start_engine()` method that simulates starting the engine of the respective vehicle. Currently, to create a new vehicle, we simply instantiate the corresponding class with a specified `make` and `model`.\n\n```python\nclass Car:\n    def __init__(self, make, model):\n        self.make = make\n        self.model = model\n\n    def start_engine(self):\n        print(f\"{self.make} {self.model}: Engine started\")\n\nclass Motorcycle:\n    def __init__(self, make, model):\n        self.make = make\n        self.model = model\n\n    def start_engine(self):\n        print(f\"{self.make} {self.model}: Engine started\")\n\n# Usage\nvehicle1 = Car(\"Toyota\", \"Corolla\")\nvehicle1.start_engine()\n\nvehicle2 = Motorcycle(\"Harley-Davidson\", \"Sportster\")\nvehicle2.start_engine()\n\n```\n\nNext, we need to create vehicles that account for regional specifications — for example, US Spec and EU Spec.\n\nThe task is to implement the `Factory pattern`, which allows creating vehicles with different regional specifications without modifying the core vehicle classes.\n\n##### Steps for Task 1\n\n1. Create an abstract base class `Vehicle` with a `start_engine()` method.\n2. Update the `Car` and `Motorcycle` classes to inherit from Vehicle.\n3. Create an abstract class `VehicleFactory` with methods `create_car()` and `create_motorcycle()`.\n4. Implement two factory classes: `USVehicleFactory` and `EUVehicleFactory`. These factories should create vehicles labeled with the appropriate regional spec, for example, `Ford Mustang (US Spec)` for the US.\n5. Refactor the initial code to use these factories for creating vehicles.\n\n##### Expected Result\n\n* Code that makes it easy to create vehicles for different regions using the appropriate factory.\n\n#### Task 2: SOLID Principles\n\n##### Task description\n\nThere is a simplified program for managing a library of books. The program allows adding new books, removing books, and displaying all books in the library. The user can interact with the program via command-line using commands: `add`, `remove`, `show`, and `exit`.\n\n```python\nclass Library:\n    def __init__(self):\n        self.books = []\n\n    def add_book(self, title, author, year):\n        book = {\n            \"title\": title,\n            \"author\": author,\n            \"year\": year\n        }\n        self.books.append(book)\n\n    def remove_book(self, title):\n        for book in self.books:\n            if book[\"title\"] == title:\n                self.books.remove(book)\n                break\n\n    def show_books(self):\n        for book in self.books:\n            print(f'Title: {book[\"title\"]}, Author: {book[\"author\"]}, Year: {book[\"year\"]}')\n\ndef main():\n    library = Library()\n\n    while True:\n        command = input(\"Enter command (add, remove, show, exit): \").strip().lower()\n\n        if command == \"add\":\n            title = input(\"Enter book title: \").strip()\n            author = input(\"Enter book author: \").strip()\n            year = input(\"Enter book year: \").strip()\n            library.add_book(title, author, year)\n        elif command == \"remove\":\n            title = input(\"Enter book title to remove: \").strip()\n            library.remove_book(title)\n        elif command == \"show\":\n            library.show_books()\n        elif command == \"exit\":\n            break\n        else:\n            print(\"Invalid command. Please try again.\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\nThe task is to rewrite this code following the SOLID principles.\n\n##### Steps for Task 2\n\n1. **Single Responsibility Principle (SRP)**: Create a `Book` class that is responsible for storing book information.\n2. **Open/Closed Principle (OCP)**: Design the `Library` class so that it can be extended with new functionality without modifying its existing code.\n3. **Liskov Substitution Principle (LSP)**: Ensure that any class inheriting from the `LibraryInterface` can replace the `Library` class without breaking the program.\n4. **Interface Segregation Principle (ISP)**: Use a `LibraryInterface` to clearly specify the methods required to work with the library.\n5. **Dependency Inversion Principle (DIP)**: High-level classes like `LibraryManager` should depend on abstractions (interfaces), not concrete implementations.\n\n```python\nfrom abc import ABC, abstractmethod\n\nclass Book:\n    pass\n\nclass LibraryInterface(ABC):\n    pass\n\nclass Library(LibraryInterface):\n    pass\n\nclass LibraryManager:\n    pass\n\ndef main():\n    library = Library()\n    manager = LibraryManager(library)\n\n    while True:\n        command = input(\"Enter command (add, remove, show, exit): \").strip().lower()\n\n        match command:\n            case \"add\":\n                title = input(\"Enter book title: \").strip()\n                author = input(\"Enter book author: \").strip()\n                year = input(\"Enter book year: \").strip()\n                manager.add_book(title, author, year)\n            case \"remove\":\n                title = input(\"Enter book title to remove: \").strip()\n                manager.remove_book(title)\n            case \"show\":\n                manager.show_books()\n            case \"exit\":\n                break\n            case _:\n                print(\"Invalid command. Please try again.\")\n\nif __name__ == \"__main__\":\n    main()\n```\n\n\n### Task Solution\n\n##### Task 1 solution\n\nSolution for this task is located in the following file:\n* [src/goit_pythonweb_hw_01/task_1/main.py](./src/goit_pythonweb_hw_01/task_1/main.py) - developed solution for task 1.\n\n![UML Class Diagram](./assets/uml/task_1.jpg)\n\nApplication screenshot:\n\n![task solution terminal screenshot](./assets/results/task_1_screenshot.png)\n\n##### Task 2 solution\n\nSolution for this task is located in the following file:\n[src/goit_pythonweb_hw_01/task_2/main.py](./src/goit_pythonweb_hw_01/task_2/main.py) - developed solution for task 2.\n\n![UML Class Diagram](./assets/uml/task_2.jpg)\n\nApplication screenshot:\n\n![task solution terminal screenshot](./assets/results/task_2_screenshot.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foleksandr-romashko%2Fgoit-pythonweb-hw-01","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foleksandr-romashko%2Fgoit-pythonweb-hw-01","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foleksandr-romashko%2Fgoit-pythonweb-hw-01/lists"}