├── chapter_4 ├── itam │ ├── __init__.py │ ├── infrastructure │ │ ├── api │ │ │ ├── __init__.py │ │ │ └── asset_model.py │ │ ├── ports │ │ │ └── asset_rest_port.py │ │ ├── repository │ │ │ ├── base_repository.py │ │ │ ├── sqlalchemy_asset_repository.py │ │ │ └── in_memory_asset_repository.py │ │ ├── adapters │ │ │ ├── asset_rest_adapter.py │ │ │ └── asset_database_adapter.py │ │ └── database │ │ │ └── database_connection.py │ ├── service │ │ ├── __init__.py │ │ └── asset_manager.py │ ├── visitor │ │ ├── __init__.py │ │ └── department_visitor.py │ └── domain │ │ ├── department.py │ │ ├── organization.py │ │ ├── role.py │ │ ├── address.py │ │ ├── snowflake_identifier.py │ │ ├── budget.py │ │ ├── location.py │ │ ├── warranty.py │ │ ├── maintenance_schedule.py │ │ ├── __init__.py │ │ ├── funding_details.py │ │ ├── user.py │ │ ├── line_of_business_statistics.py │ │ ├── factory │ │ └── asset_factory.py │ │ ├── asset.py │ │ ├── software.py │ │ ├── depreciation_strategy.py │ │ └── hardware.py ├── README.md ├── requirements.txt ├── main.py └── diagram2.mmd ├── chapter_5 ├── itam │ ├── __init__.py │ ├── infrastructure │ │ ├── api │ │ │ ├── __init__.py │ │ │ └── asset_model.py │ │ ├── mediators │ │ │ └── asset_location_mediator.py │ │ ├── ports │ │ │ └── asset_rest_port.py │ │ ├── repository │ │ │ ├── base_repository.py │ │ │ └── in_memory_asset_repository.py │ │ ├── adapters │ │ │ ├── asset_rest_adapter.py │ │ │ └── asset_database_adapter.py │ │ ├── consumers │ │ │ └── asset_location_kafka_consumer.py │ │ └── database │ │ │ └── database_connection.py │ ├── service │ │ ├── __init__.py │ │ └── asset_manager.py │ ├── visitor │ │ ├── __init__.py │ │ └── department_visitor.py │ └── domain │ │ ├── department.py │ │ ├── events │ │ └── asset_location_updated.py │ │ ├── organization.py │ │ ├── role.py │ │ ├── location.py │ │ ├── address.py │ │ ├── snowflake_identifier.py │ │ ├── budget.py │ │ ├── warranty.py │ │ ├── maintenance_schedule.py │ │ ├── __init__.py │ │ ├── funding_details.py │ │ ├── user.py │ │ ├── line_of_business_statistics.py │ │ ├── factory │ │ └── asset_factory.py │ │ ├── software.py │ │ ├── depreciation_strategy.py │ │ └── hardware.py ├── .gitignore ├── requirements.txt ├── data │ └── scripts │ │ └── load.sql ├── README.md ├── docker-compose.yml ├── diagram2.mmd └── main.py ├── chapter_2 ├── chatgpt-fastapi │ ├── gpt-itam-env │ │ ├── bin │ │ │ ├── python │ │ │ ├── python3 │ │ │ ├── python3.10 │ │ │ ├── flask │ │ │ ├── uvicorn │ │ │ ├── pip │ │ │ ├── pip3 │ │ │ ├── pip3.10 │ │ │ └── activate.csh │ │ └── pyvenv.cfg │ ├── requirements.txt │ ├── requirements.Flask.txt │ ├── README.md │ ├── asset.Flask.py │ ├── asset_manager.Flask.py │ ├── asset_manager.py │ └── asset.py ├── chatgpt-flask │ ├── requirements.txt │ ├── gpt-itam-env │ │ ├── pyvenv.cfg │ │ └── bin │ │ │ ├── python │ │ │ ├── python3 │ │ │ ├── python3.10 │ │ │ ├── flask │ │ │ ├── uvicorn │ │ │ ├── pip │ │ │ ├── pip3 │ │ │ ├── pip3.10 │ │ │ └── activate.csh │ ├── requirements.Flask.txt │ ├── README.md │ ├── asset.Flask.py │ ├── asset_manager.Flask.py │ ├── asset_manager.py │ └── asset.py ├── copilot │ ├── .vscode │ │ └── settings.json │ ├── .metals │ │ └── metals.mv.db │ ├── requirements.txt │ ├── asset_manager.py │ ├── app.py │ └── asset.py └── code-whisperer │ └── asset.py ├── chapter_6 ├── .gitignore ├── itam │ ├── infrastructure │ │ ├── api │ │ │ ├── __init__.py │ │ │ └── asset_model.py │ │ ├── __init__.py │ │ ├── mediators │ │ │ └── asset_location_mediator.py │ │ ├── ports │ │ │ └── asset_rest_port.py │ │ ├── repository │ │ │ ├── base_repository.py │ │ │ └── in_memory_asset_repository.py │ │ ├── adapters │ │ │ ├── asset_rest_adapter.py │ │ │ └── asset_database_adapter.py │ │ ├── consumers │ │ │ └── asset_location_kafka_consumer.py │ │ └── database │ │ │ └── database_connection.py │ ├── service │ │ ├── __init__.py │ │ └── asset_manager.py │ ├── __init__.py │ ├── visitor │ │ ├── __init__.py │ │ └── test_department_visitor.py │ └── domain │ │ ├── events │ │ └── asset_location_updated.py │ │ ├── department.py │ │ ├── organization.py │ │ ├── role.py │ │ ├── location.py │ │ ├── address.py │ │ ├── snowflake_identifier.py │ │ ├── budget.py │ │ ├── warranty.py │ │ ├── maintenance_schedule.py │ │ ├── __init__.py │ │ ├── user.py │ │ ├── funding_details.py │ │ ├── line_of_business_statistics.py │ │ ├── factory │ │ └── asset_factory.py │ │ ├── software.py │ │ └── hardware.py ├── requirements.txt ├── features │ ├── asset_manager.feature │ └── steps │ │ └── steps.py ├── data │ └── scripts │ │ └── load.sql ├── README.md ├── docker-compose.yml ├── diagram2.mmd └── main.py ├── chapter_7 ├── .gitignore ├── itam │ ├── infrastructure │ │ ├── api │ │ │ ├── __init__.py │ │ │ └── asset_model.py │ │ ├── __init__.py │ │ ├── mediators │ │ │ └── asset_location_mediator.py │ │ ├── ports │ │ │ └── asset_rest_port.py │ │ ├── repository │ │ │ ├── base_repository.py │ │ │ └── in_memory_asset_repository.py │ │ ├── adapters │ │ │ ├── asset_rest_adapter.py │ │ │ └── asset_database_adapter.py │ │ ├── consumers │ │ │ └── asset_location_kafka_consumer.py │ │ └── database │ │ │ └── database_connection.py │ ├── service │ │ ├── __init__.py │ │ └── asset_manager.py │ ├── __init__.py │ ├── visitor │ │ ├── __init__.py │ │ └── test_department_visitor.py │ └── domain │ │ ├── events │ │ └── asset_location_updated.py │ │ ├── department.py │ │ ├── organization.py │ │ ├── role.py │ │ ├── location.py │ │ ├── address.py │ │ ├── snowflake_identifier.py │ │ ├── budget.py │ │ ├── warranty.py │ │ ├── maintenance_schedule.py │ │ ├── __init__.py │ │ ├── user.py │ │ ├── funding_details.py │ │ ├── line_of_business_statistics.py │ │ ├── factory │ │ └── asset_factory.py │ │ ├── software.py │ │ └── hardware.py ├── README.md ├── requirements.txt ├── features │ ├── asset_manager.feature │ └── steps │ │ └── steps.py ├── data │ └── scripts │ │ └── load.sql ├── docker-compose.yml ├── diagram2.mmd └── main.py ├── README.md └── chapter_9 ├── .idea ├── vcs.xml ├── .gitignore ├── misc.xml ├── inspectionProfiles │ ├── profiles_settings.xml │ └── Project_Default.xml ├── modules.xml └── chapter_9.iml └── main.py /chapter_4/itam/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter_5/itam/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /chapter_4/README.md: -------------------------------------------------------------------------------- 1 | # The AI-Assisted Developer Chapter 4 -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/python: -------------------------------------------------------------------------------- 1 | python3.10 -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/python3: -------------------------------------------------------------------------------- 1 | python3.10 -------------------------------------------------------------------------------- /chapter_5/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .vscode 4 | .env 5 | .venv -------------------------------------------------------------------------------- /chapter_6/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .vscode 4 | .env 5 | .venv -------------------------------------------------------------------------------- /chapter_7/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | .vscode 4 | .env 5 | .venv -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The public source code repository for the Manning book - AI Powered Developer 2 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/python3.10: -------------------------------------------------------------------------------- 1 | /opt/homebrew/opt/python@3.10/bin/python3.10 -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.70.0 2 | uvicorn==0.15.0 3 | pydantic==1.8.2 4 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi==0.70.0 2 | uvicorn==0.15.0 3 | pydantic==1.8.2 4 | -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/api/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_model import AssetIn 2 | 3 | all = ['AssetIn'] -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/api/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_model import AssetIn 2 | 3 | all = ['AssetIn'] -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/api/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_model import AssetIn 2 | 3 | all = ['AssetIn'] -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/api/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_model import AssetIn 2 | 3 | all = ['AssetIn'] -------------------------------------------------------------------------------- /chapter_2/copilot/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.watcherExclude": { 3 | "**/target": true 4 | } 5 | } -------------------------------------------------------------------------------- /chapter_4/itam/service/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_manager import AssetManager 2 | 3 | __all__ = [ 4 | 'AssetManager', 5 | ] -------------------------------------------------------------------------------- /chapter_5/itam/service/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_manager import AssetManager 2 | 3 | __all__ = [ 4 | 'AssetManager', 5 | ] -------------------------------------------------------------------------------- /chapter_6/itam/service/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_manager import AssetManager 2 | 3 | __all__ = [ 4 | 'AssetManager', 5 | ] -------------------------------------------------------------------------------- /chapter_7/itam/service/__init__.py: -------------------------------------------------------------------------------- 1 | from .asset_manager import AssetManager 2 | 3 | __all__ = [ 4 | 'AssetManager', 5 | ] -------------------------------------------------------------------------------- /chapter_6/itam/__init__.py: -------------------------------------------------------------------------------- 1 | from .infrastructure import * 2 | from .domain import * 3 | from .service import * 4 | from .visitor import * 5 | -------------------------------------------------------------------------------- /chapter_7/itam/__init__.py: -------------------------------------------------------------------------------- 1 | from .infrastructure import * 2 | from .domain import * 3 | from .service import * 4 | from .visitor import * 5 | -------------------------------------------------------------------------------- /chapter_2/copilot/.metals/metals.mv.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanbcrocker/ai_powered_developer/HEAD/chapter_2/copilot/.metals/metals.mv.db -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /opt/homebrew/opt/python@3.10/bin 2 | include-system-site-packages = false 3 | version = 3.10.6 4 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/pyvenv.cfg: -------------------------------------------------------------------------------- 1 | home = /opt/homebrew/opt/python@3.10/bin 2 | include-system-site-packages = false 3 | version = 3.10.6 4 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/python: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanbcrocker/ai_powered_developer/HEAD/chapter_2/chatgpt-flask/gpt-itam-env/bin/python -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/python3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanbcrocker/ai_powered_developer/HEAD/chapter_2/chatgpt-flask/gpt-itam-env/bin/python3 -------------------------------------------------------------------------------- /chapter_2/copilot/requirements.txt: -------------------------------------------------------------------------------- 1 | # generate a requirements.txt file for this project 2 | fastapi==0.63.0 3 | uvicorn==0.13.4 4 | pydantic==1.7.3 5 | starlette==0.13.6 -------------------------------------------------------------------------------- /chapter_4/requirements.txt: -------------------------------------------------------------------------------- 1 | # pip install uvicorn 2 | # pip install fastapi 3 | 4 | uvicorn==0.11.8 5 | fastapi==0.61.1 6 | psycopg2-binary==2.9.6 7 | SQLAlchemy==2.0.9 -------------------------------------------------------------------------------- /chapter_7/README.md: -------------------------------------------------------------------------------- 1 | # The AI-Assisted Developer Chapter 7 2 | 3 | Dockerfiles are not currently supported by AWS CodeWhisperer 4 | Copilot does not support Terraform -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/python3.10: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanbcrocker/ai_powered_developer/HEAD/chapter_2/chatgpt-flask/gpt-itam-env/bin/python3.10 -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/__init__.py: -------------------------------------------------------------------------------- 1 | from .adapters import * 2 | from .api import * 3 | from .consumers import * 4 | from .database import * 5 | from .mediators import * 6 | from .ports import * 7 | from.repository import * -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/__init__.py: -------------------------------------------------------------------------------- 1 | from .adapters import * 2 | from .api import * 3 | from .consumers import * 4 | from .database import * 5 | from .mediators import * 6 | from .ports import * 7 | from.repository import * -------------------------------------------------------------------------------- /chapter_9/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/requirements.Flask.txt: -------------------------------------------------------------------------------- 1 | click==8.0.3 2 | Flask==2.1.1 3 | importlib-metadata==4.8.1 4 | itsdangerous==2.0.1 5 | Jinja2==3.0.2 6 | MarkupSafe==2.0.1 7 | typing-extensions==3.10.0.2 8 | Werkzeug==2.0.1 9 | zipp==3.6.0 -------------------------------------------------------------------------------- /chapter_9/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /chapter_9/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/requirements.Flask.txt: -------------------------------------------------------------------------------- 1 | click==8.0.3 2 | Flask==2.1.1 3 | importlib-metadata==4.8.1 4 | itsdangerous==2.0.1 5 | Jinja2==3.0.2 6 | MarkupSafe==2.0.1 7 | typing-extensions==3.10.0.2 8 | Werkzeug==2.0.1 9 | zipp==3.6.0 -------------------------------------------------------------------------------- /chapter_9/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /chapter_4/itam/visitor/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the visitor module 2 | 3 | from .department_visitor import DepartmentVisitor, DepartmentStatisticsVisitor 4 | 5 | __all__ = [ 6 | "DepartmentVisitor", 7 | "DepartmentStatisticsVisitor" 8 | ] 9 | -------------------------------------------------------------------------------- /chapter_5/itam/visitor/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the visitor module 2 | 3 | from .department_visitor import DepartmentVisitor, DepartmentStatisticsVisitor 4 | 5 | __all__ = [ 6 | "DepartmentVisitor", 7 | "DepartmentStatisticsVisitor" 8 | ] 9 | -------------------------------------------------------------------------------- /chapter_6/itam/visitor/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the visitor module 2 | 3 | from .department_visitor import DepartmentVisitor, DepartmentStatisticsVisitor 4 | 5 | __all__ = [ 6 | "DepartmentVisitor", 7 | "DepartmentStatisticsVisitor" 8 | ] 9 | -------------------------------------------------------------------------------- /chapter_7/itam/visitor/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the visitor module 2 | 3 | from .department_visitor import DepartmentVisitor, DepartmentStatisticsVisitor 4 | 5 | __all__ = [ 6 | "DepartmentVisitor", 7 | "DepartmentStatisticsVisitor" 8 | ] 9 | -------------------------------------------------------------------------------- /chapter_4/itam/domain/department.py: -------------------------------------------------------------------------------- 1 | # define a class called Department, using Python's built-in dataclass decorator. 2 | # The Department entity has two attributes: id: int, name: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Department: 8 | id: int 9 | name: str -------------------------------------------------------------------------------- /chapter_5/itam/domain/department.py: -------------------------------------------------------------------------------- 1 | # define a class called Department, using Python's built-in dataclass decorator. 2 | # The Department entity has two attributes: id: int, name: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Department: 8 | id: int 9 | name: str -------------------------------------------------------------------------------- /chapter_5/requirements.txt: -------------------------------------------------------------------------------- 1 | # pip install uvicorn 2 | # pip install fastapi 3 | 4 | uvicorn==0.22.0 5 | fastapi==0.95.1 6 | psycopg2-binary==2.9.6 7 | SQLAlchemy==2.0.13 8 | pandas==2.0.1 9 | numpy==1.24.3 10 | kafka-python==2.0.2 11 | pyspark==3.4.0 12 | asyncio==3.4.3 13 | geopy==2.2.0 14 | -------------------------------------------------------------------------------- /chapter_9/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /chapter_9/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/flask: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from flask.cli import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/flask: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from flask.cli import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/uvicorn: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from uvicorn.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/uvicorn: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from uvicorn.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/pip: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from pip._internal.cli.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/pip3: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from pip._internal.cli.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_5/itam/domain/events/asset_location_updated.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | class AssetLocationUpdated: 4 | def __init__(self, asset_id: int, latitude: float, longitude: float, timestamp: date): 5 | self.asset_id = asset_id 6 | self.latitude = latitude 7 | self.longitude = longitude 8 | self.timestamp = timestamp -------------------------------------------------------------------------------- /chapter_6/itam/domain/events/asset_location_updated.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | class AssetLocationUpdated: 4 | def __init__(self, asset_id: int, latitude: float, longitude: float, timestamp: date): 5 | self.asset_id = asset_id 6 | self.latitude = latitude 7 | self.longitude = longitude 8 | self.timestamp = timestamp -------------------------------------------------------------------------------- /chapter_6/requirements.txt: -------------------------------------------------------------------------------- 1 | # pip install uvicorn 2 | # pip install fastapi 3 | 4 | uvicorn==0.22.0 5 | fastapi==0.95.1 6 | psycopg2-binary==2.9.6 7 | SQLAlchemy==2.0.13 8 | pandas==2.0.1 9 | numpy==1.24.3 10 | kafka-python==2.0.2 11 | pyspark==3.4.0 12 | asyncio==3.4.3 13 | geopy==2.2.0 14 | httpx==0.19.0 15 | pytest==7.3.1 16 | behave==1.2.6 17 | -------------------------------------------------------------------------------- /chapter_7/itam/domain/events/asset_location_updated.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | class AssetLocationUpdated: 4 | def __init__(self, asset_id: int, latitude: float, longitude: float, timestamp: date): 5 | self.asset_id = asset_id 6 | self.latitude = latitude 7 | self.longitude = longitude 8 | self.timestamp = timestamp -------------------------------------------------------------------------------- /chapter_7/requirements.txt: -------------------------------------------------------------------------------- 1 | # pip install uvicorn 2 | # pip install fastapi 3 | 4 | uvicorn==0.22.0 5 | fastapi==0.95.1 6 | psycopg2-binary==2.9.6 7 | SQLAlchemy==2.0.13 8 | pandas==2.0.1 9 | numpy==1.24.3 10 | kafka-python==2.0.2 11 | pyspark==3.4.0 12 | asyncio==3.4.3 13 | geopy==2.2.0 14 | httpx==0.19.0 15 | pytest==7.3.1 16 | behave==1.2.6 17 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/pip: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from pip._internal.cli.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/pip3: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from pip._internal.cli.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/pip3.10: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from pip._internal.cli.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/pip3.10: -------------------------------------------------------------------------------- 1 | #!/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env/bin/python3.10 2 | # -*- coding: utf-8 -*- 3 | import re 4 | import sys 5 | from pip._internal.cli.main import main 6 | if __name__ == '__main__': 7 | sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) 8 | sys.exit(main()) 9 | -------------------------------------------------------------------------------- /chapter_6/itam/domain/department.py: -------------------------------------------------------------------------------- 1 | # define a class called Department, using Python's built-in dataclass decorator. 2 | # The Department entity has two attributes: id: int, name: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Department: 8 | id: int 9 | name: str 10 | 11 | def __hash__(self): 12 | return hash(self.id) -------------------------------------------------------------------------------- /chapter_7/itam/domain/department.py: -------------------------------------------------------------------------------- 1 | # define a class called Department, using Python's built-in dataclass decorator. 2 | # The Department entity has two attributes: id: int, name: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Department: 8 | id: int 9 | name: str 10 | 11 | def __hash__(self): 12 | return hash(self.id) -------------------------------------------------------------------------------- /chapter_4/itam/domain/organization.py: -------------------------------------------------------------------------------- 1 | # define the Organization entity using Python's built-in dataclass decorator. The Organization entity has two attributes: id and name. 2 | 3 | from dataclasses import dataclass 4 | 5 | @dataclass 6 | class Organization: 7 | id: int 8 | name: str 9 | 10 | def __post_init__(self): 11 | if self.id is None: 12 | raise TypeError("Id cannot be None") -------------------------------------------------------------------------------- /chapter_5/itam/domain/organization.py: -------------------------------------------------------------------------------- 1 | # define the Organization entity using Python's built-in dataclass decorator. The Organization entity has two attributes: id and name. 2 | 3 | from dataclasses import dataclass 4 | 5 | @dataclass 6 | class Organization: 7 | id: int 8 | name: str 9 | 10 | def __post_init__(self): 11 | if self.id is None: 12 | raise TypeError("Id cannot be None") -------------------------------------------------------------------------------- /chapter_6/itam/domain/organization.py: -------------------------------------------------------------------------------- 1 | # define the Organization entity using Python's built-in dataclass decorator. The Organization entity has two attributes: id and name. 2 | 3 | from dataclasses import dataclass 4 | 5 | @dataclass 6 | class Organization: 7 | id: int 8 | name: str 9 | 10 | def __post_init__(self): 11 | if self.id is None: 12 | raise TypeError("Id cannot be None") -------------------------------------------------------------------------------- /chapter_7/itam/domain/organization.py: -------------------------------------------------------------------------------- 1 | # define the Organization entity using Python's built-in dataclass decorator. The Organization entity has two attributes: id and name. 2 | 3 | from dataclasses import dataclass 4 | 5 | @dataclass 6 | class Organization: 7 | id: int 8 | name: str 9 | 10 | def __post_init__(self): 11 | if self.id is None: 12 | raise TypeError("Id cannot be None") -------------------------------------------------------------------------------- /chapter_9/.idea/chapter_9.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /chapter_4/itam/domain/role.py: -------------------------------------------------------------------------------- 1 | # Create a class called Role. 2 | # The Role entity has the following attributes: 3 | # - id: int, 4 | # - name: str 5 | # none of the attributes can be None 6 | 7 | from dataclasses import dataclass 8 | 9 | @dataclass 10 | class Role: 11 | id: int 12 | name: str 13 | 14 | def __post_init__(self): 15 | if self.id is None: 16 | raise TypeError("Id cannot be None") 17 | if self.name is None: 18 | raise TypeError("Name cannot be None") -------------------------------------------------------------------------------- /chapter_5/itam/domain/role.py: -------------------------------------------------------------------------------- 1 | # Create a class called Role. 2 | # The Role entity has the following attributes: 3 | # - id: int, 4 | # - name: str 5 | # none of the attributes can be None 6 | 7 | from dataclasses import dataclass 8 | 9 | @dataclass 10 | class Role: 11 | id: int 12 | name: str 13 | 14 | def __post_init__(self): 15 | if self.id is None: 16 | raise TypeError("Id cannot be None") 17 | if self.name is None: 18 | raise TypeError("Name cannot be None") -------------------------------------------------------------------------------- /chapter_6/itam/domain/role.py: -------------------------------------------------------------------------------- 1 | # Create a class called Role. 2 | # The Role entity has the following attributes: 3 | # - id: int, 4 | # - name: str 5 | # none of the attributes can be None 6 | 7 | from dataclasses import dataclass 8 | 9 | @dataclass 10 | class Role: 11 | id: int 12 | name: str 13 | 14 | def __post_init__(self): 15 | if self.id is None: 16 | raise TypeError("Id cannot be None") 17 | if self.name is None: 18 | raise TypeError("Name cannot be None") -------------------------------------------------------------------------------- /chapter_7/itam/domain/role.py: -------------------------------------------------------------------------------- 1 | # Create a class called Role. 2 | # The Role entity has the following attributes: 3 | # - id: int, 4 | # - name: str 5 | # none of the attributes can be None 6 | 7 | from dataclasses import dataclass 8 | 9 | @dataclass 10 | class Role: 11 | id: int 12 | name: str 13 | 14 | def __post_init__(self): 15 | if self.id is None: 16 | raise TypeError("Id cannot be None") 17 | if self.name is None: 18 | raise TypeError("Name cannot be None") -------------------------------------------------------------------------------- /chapter_6/features/asset_manager.feature: -------------------------------------------------------------------------------- 1 | Feature: Asset Manager 2 | As an IT Asset Manager 3 | I want to be able to manage assets 4 | So that I can keep track of all IT assets in my organization 5 | 6 | Scenario: Add two assets to the Asset Manager 7 | Given the Asset Manager is running 8 | And the InMemoryAssetRepository is initialized 9 | And the AssetLocationMediator is mocked 10 | When I create an asset with a cost of $2000.00 11 | And I create another asset with a cost of $2000.00 12 | Then the total cost of all assets should be $4000.00 -------------------------------------------------------------------------------- /chapter_7/features/asset_manager.feature: -------------------------------------------------------------------------------- 1 | Feature: Asset Manager 2 | As an IT Asset Manager 3 | I want to be able to manage assets 4 | So that I can keep track of all IT assets in my organization 5 | 6 | Scenario: Add two assets to the Asset Manager 7 | Given the Asset Manager is running 8 | And the InMemoryAssetRepository is initialized 9 | And the AssetLocationMediator is mocked 10 | When I create an asset with a cost of $2000.00 11 | And I create another asset with a cost of $2000.00 12 | Then the total cost of all assets should be $4000.00 -------------------------------------------------------------------------------- /chapter_5/itam/domain/location.py: -------------------------------------------------------------------------------- 1 | # define the Location entity using Python's built-in dataclass decorator. 2 | # The Location entity has four attributes: id: int, name: str, address: Address, and organization: Organization which is optional. 3 | 4 | from dataclasses import dataclass 5 | from itam.domain.address import Address 6 | from itam.domain.organization import Organization 7 | from typing import Optional 8 | from datetime import date 9 | 10 | @dataclass 11 | class Location: 12 | asset_id: int 13 | latitude: float 14 | longitude: float 15 | timestamp: date -------------------------------------------------------------------------------- /chapter_6/itam/domain/location.py: -------------------------------------------------------------------------------- 1 | # define the Location entity using Python's built-in dataclass decorator. 2 | # The Location entity has four attributes: id: int, name: str, address: Address, and organization: Organization which is optional. 3 | 4 | from dataclasses import dataclass 5 | from itam.domain.address import Address 6 | from itam.domain.organization import Organization 7 | from typing import Optional 8 | from datetime import date 9 | 10 | @dataclass 11 | class Location: 12 | asset_id: int 13 | latitude: float 14 | longitude: float 15 | timestamp: date -------------------------------------------------------------------------------- /chapter_7/itam/domain/location.py: -------------------------------------------------------------------------------- 1 | # define the Location entity using Python's built-in dataclass decorator. 2 | # The Location entity has four attributes: id: int, name: str, address: Address, and organization: Organization which is optional. 3 | 4 | from dataclasses import dataclass 5 | from itam.domain.address import Address 6 | from itam.domain.organization import Organization 7 | from typing import Optional 8 | from datetime import date 9 | 10 | @dataclass 11 | class Location: 12 | asset_id: int 13 | latitude: float 14 | longitude: float 15 | timestamp: date -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/mediators/asset_location_mediator.py: -------------------------------------------------------------------------------- 1 | 2 | class AssetLocationMediator: 3 | 4 | def __init__(self): 5 | self.handlers = {} 6 | 7 | def register_handler(self, event_type, handler): 8 | if event_type not in self.handlers: 9 | self.handlers[event_type] = [] 10 | self.handlers[event_type].append(handler) 11 | 12 | def publish(self, event): 13 | event_type = type(event) 14 | if event_type in self.handlers: 15 | for handler in self.handlers[event_type]: 16 | handler(event) -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/mediators/asset_location_mediator.py: -------------------------------------------------------------------------------- 1 | 2 | class AssetLocationMediator: 3 | 4 | def __init__(self): 5 | self.handlers = {} 6 | 7 | def register_handler(self, event_type, handler): 8 | if event_type not in self.handlers: 9 | self.handlers[event_type] = [] 10 | self.handlers[event_type].append(handler) 11 | 12 | def publish(self, event): 13 | event_type = type(event) 14 | if event_type in self.handlers: 15 | for handler in self.handlers[event_type]: 16 | handler(event) -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/mediators/asset_location_mediator.py: -------------------------------------------------------------------------------- 1 | 2 | class AssetLocationMediator: 3 | 4 | def __init__(self): 5 | self.handlers = {} 6 | 7 | def register_handler(self, event_type, handler): 8 | if event_type not in self.handlers: 9 | self.handlers[event_type] = [] 10 | self.handlers[event_type].append(handler) 11 | 12 | def publish(self, event): 13 | event_type = type(event) 14 | if event_type in self.handlers: 15 | for handler in self.handlers[event_type]: 16 | handler(event) -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/ports/asset_rest_port.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestPort 2 | # It should expose all of the methods in AssetManager as abtract methods 3 | 4 | from itam.domain.asset import Asset 5 | from abc import abstractmethod 6 | 7 | class AssetRestPort: 8 | @abstractmethod 9 | def read(self, asset_id: int) -> Asset: 10 | pass 11 | 12 | @abstractmethod 13 | def create(self, asset: Asset) -> None: 14 | pass 15 | 16 | @abstractmethod 17 | def update(self, asset: Asset) -> None: 18 | pass 19 | 20 | @abstractmethod 21 | def delete(self, asset_id: int) -> None: 22 | pass 23 | 24 | @abstractmethod 25 | def get_assets(self): 26 | pass -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 2 Using ChatGPT 2 | 3 | To run: 4 | 5 | `pip install virtualenv` 6 | 7 | `python3 -m venv gpt-itam-env` 8 | 9 | `source gpt-itam-env/bin/activate` 10 | 11 | `pip install -r requirements.txt` 12 | 13 | 14 | curl -X POST "http://localhost:8000/assets/" -d "{'asset_id':'003', \ 15 | 'asset_type': 'Server', \ 16 | 'manufacturer': 'Dell', \ 17 | 'model': 'PowerEdge R740', \ 18 | 'purchase_date': '2021-03-01', \ 19 | 'warranty_end_date': '2024-03-01', \ 20 | 'location': 'London' \ 21 | }" 22 | 23 | '003', , ', 'PowerEdge R740', '2021-03-01', , ) 24 | 25 | curl -X PUT -H "Content-Type: application/json" -d '{"asset_id": "12345", "user": "John"}' http://localhost:8000/assets/12345/assign 26 | -------------------------------------------------------------------------------- /chapter_4/itam/domain/address.py: -------------------------------------------------------------------------------- 1 | # Define the Address entity using Python's built-in dataclass decorator. 2 | # The Address entity has four attributes: street: str, city: str, state: str, and zip_code: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Address: 8 | street: str 9 | city: str 10 | state: str 11 | zip_code: str 12 | 13 | def __post_init__(self): 14 | if self.street is None: 15 | raise TypeError("Street cannot be None") 16 | if self.city is None: 17 | raise TypeError("City cannot be None") 18 | if self.state is None: 19 | raise TypeError("State cannot be None") 20 | if self.zip_code is None: 21 | raise TypeError("Zip Code cannot be None") -------------------------------------------------------------------------------- /chapter_5/itam/domain/address.py: -------------------------------------------------------------------------------- 1 | # Define the Address entity using Python's built-in dataclass decorator. 2 | # The Address entity has four attributes: street: str, city: str, state: str, and zip_code: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Address: 8 | street: str 9 | city: str 10 | state: str 11 | zip_code: str 12 | 13 | def __post_init__(self): 14 | if self.street is None: 15 | raise TypeError("Street cannot be None") 16 | if self.city is None: 17 | raise TypeError("City cannot be None") 18 | if self.state is None: 19 | raise TypeError("State cannot be None") 20 | if self.zip_code is None: 21 | raise TypeError("Zip Code cannot be None") -------------------------------------------------------------------------------- /chapter_6/itam/domain/address.py: -------------------------------------------------------------------------------- 1 | # Define the Address entity using Python's built-in dataclass decorator. 2 | # The Address entity has four attributes: street: str, city: str, state: str, and zip_code: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Address: 8 | street: str 9 | city: str 10 | state: str 11 | zip_code: str 12 | 13 | def __post_init__(self): 14 | if self.street is None: 15 | raise TypeError("Street cannot be None") 16 | if self.city is None: 17 | raise TypeError("City cannot be None") 18 | if self.state is None: 19 | raise TypeError("State cannot be None") 20 | if self.zip_code is None: 21 | raise TypeError("Zip Code cannot be None") -------------------------------------------------------------------------------- /chapter_7/itam/domain/address.py: -------------------------------------------------------------------------------- 1 | # Define the Address entity using Python's built-in dataclass decorator. 2 | # The Address entity has four attributes: street: str, city: str, state: str, and zip_code: str. 3 | 4 | from dataclasses import dataclass 5 | 6 | @dataclass 7 | class Address: 8 | street: str 9 | city: str 10 | state: str 11 | zip_code: str 12 | 13 | def __post_init__(self): 14 | if self.street is None: 15 | raise TypeError("Street cannot be None") 16 | if self.city is None: 17 | raise TypeError("City cannot be None") 18 | if self.state is None: 19 | raise TypeError("State cannot be None") 20 | if self.zip_code is None: 21 | raise TypeError("Zip Code cannot be None") -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/ports/asset_rest_port.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestPort 2 | # It should expose all of the methods in AssetManager as abtract methods 3 | 4 | from itam.domain.asset import Asset 5 | from abc import abstractmethod 6 | from typing import List 7 | 8 | class AssetRestPort: 9 | @abstractmethod 10 | def read(self, asset_id: int) -> Asset: 11 | pass 12 | 13 | @abstractmethod 14 | def create(self, asset: Asset) -> None: 15 | pass 16 | 17 | @abstractmethod 18 | def update(self, asset: Asset) -> None: 19 | pass 20 | 21 | @abstractmethod 22 | def delete(self, asset_id: int) -> None: 23 | pass 24 | 25 | @abstractmethod 26 | def get_assets(self) -> List[Asset]: 27 | pass -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/ports/asset_rest_port.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestPort 2 | # It should expose all of the methods in AssetManager as abtract methods 3 | 4 | from itam.domain.asset import Asset 5 | from abc import abstractmethod 6 | from typing import List 7 | 8 | class AssetRestPort: 9 | @abstractmethod 10 | def read(self, asset_id: int) -> Asset: 11 | pass 12 | 13 | @abstractmethod 14 | def create(self, asset: Asset) -> None: 15 | pass 16 | 17 | @abstractmethod 18 | def update(self, asset: Asset) -> None: 19 | pass 20 | 21 | @abstractmethod 22 | def delete(self, asset_id: int) -> None: 23 | pass 24 | 25 | @abstractmethod 26 | def get_assets(self) -> List[Asset]: 27 | pass -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/ports/asset_rest_port.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestPort 2 | # It should expose all of the methods in AssetManager as abtract methods 3 | 4 | from itam.domain.asset import Asset 5 | from abc import abstractmethod 6 | from typing import List 7 | 8 | class AssetRestPort: 9 | @abstractmethod 10 | def read(self, asset_id: int) -> Asset: 11 | pass 12 | 13 | @abstractmethod 14 | def create(self, asset: Asset) -> None: 15 | pass 16 | 17 | @abstractmethod 18 | def update(self, asset: Asset) -> None: 19 | pass 20 | 21 | @abstractmethod 22 | def delete(self, asset_id: int) -> None: 23 | pass 24 | 25 | @abstractmethod 26 | def get_assets(self) -> List[Asset]: 27 | pass -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/README.md: -------------------------------------------------------------------------------- 1 | # Chapter 2 Using ChatGPT 2 | 3 | To run: 4 | 5 | `pip install virtualenv` 6 | 7 | `python3 -m venv gpt-itam-env` 8 | 9 | `source gpt-itam-env/bin/activate` 10 | 11 | `pip install -r requirements.txt` 12 | 13 | `uvicorn app:app --reload` 14 | 15 | curl -X POST "http://localhost:8000/assets/" -d "{'asset_id':'003', \ 16 | 'asset_type': 'Server', \ 17 | 'manufacturer': 'Dell', \ 18 | 'model': 'PowerEdge R740', \ 19 | 'purchase_date': '2021-03-01', \ 20 | 'warranty_end_date': '2024-03-01', \ 21 | 'location': 'London' \ 22 | }" 23 | 24 | '003', , ', 'PowerEdge R740', '2021-03-01', , ) 25 | 26 | curl -X PUT -H "Content-Type: application/json" -d '{"asset_id": "12345", "user": "John"}' http://localhost:8000/assets/12345/assign 27 | -------------------------------------------------------------------------------- /chapter_4/itam/domain/snowflake_identifier.py: -------------------------------------------------------------------------------- 1 | # Define a class called SnowflakeIdentifier 2 | # It should generate an identifier using the snowflake algorithm 3 | # Combine the current time in milliseconds since the epoch time (January 1, 2021 in this case) with the machine ID and sequence number to create the ID. 4 | # The ID should be a 64-bit integer 5 | 6 | import time 7 | import uuid 8 | 9 | class SnowflakeIdentifier: 10 | def __init__(self): 11 | self._machine_id = uuid.getnode() 12 | self._sequence_number = 0 13 | self._last_timestamp = 0 14 | 15 | def get_id(self): 16 | timestamp = int(time.time() * 1000) 17 | if timestamp == self._last_timestamp: 18 | self._sequence_number += 1 19 | else: 20 | self._sequence_number = 0 21 | self._last_timestamp = timestamp 22 | return (timestamp << 22) + (self._machine_id << 10) + self._sequence_number -------------------------------------------------------------------------------- /chapter_5/itam/domain/snowflake_identifier.py: -------------------------------------------------------------------------------- 1 | # Define a class called SnowflakeIdentifier 2 | # It should generate an identifier using the snowflake algorithm 3 | # Combine the current time in milliseconds since the epoch time (January 1, 2021 in this case) with the machine ID and sequence number to create the ID. 4 | # The ID should be a 64-bit integer 5 | 6 | import time 7 | import uuid 8 | 9 | class SnowflakeIdentifier: 10 | def __init__(self): 11 | self._machine_id = uuid.getnode() 12 | self._sequence_number = 0 13 | self._last_timestamp = 0 14 | 15 | def get_id(self): 16 | timestamp = int(time.time() * 1000) 17 | if timestamp == self._last_timestamp: 18 | self._sequence_number += 1 19 | else: 20 | self._sequence_number = 0 21 | self._last_timestamp = timestamp 22 | return (timestamp << 22) + (self._machine_id << 10) + self._sequence_number -------------------------------------------------------------------------------- /chapter_6/itam/domain/snowflake_identifier.py: -------------------------------------------------------------------------------- 1 | # Define a class called SnowflakeIdentifier 2 | # It should generate an identifier using the snowflake algorithm 3 | # Combine the current time in milliseconds since the epoch time (January 1, 2021 in this case) with the machine ID and sequence number to create the ID. 4 | # The ID should be a 64-bit integer 5 | 6 | import time 7 | import uuid 8 | 9 | class SnowflakeIdentifier: 10 | def __init__(self): 11 | self._machine_id = uuid.getnode() 12 | self._sequence_number = 0 13 | self._last_timestamp = 0 14 | 15 | def get_id(self): 16 | timestamp = int(time.time() * 1000) 17 | if timestamp == self._last_timestamp: 18 | self._sequence_number += 1 19 | else: 20 | self._sequence_number = 0 21 | self._last_timestamp = timestamp 22 | return (timestamp << 22) + (self._machine_id << 10) + self._sequence_number -------------------------------------------------------------------------------- /chapter_7/itam/domain/snowflake_identifier.py: -------------------------------------------------------------------------------- 1 | # Define a class called SnowflakeIdentifier 2 | # It should generate an identifier using the snowflake algorithm 3 | # Combine the current time in milliseconds since the epoch time (January 1, 2021 in this case) with the machine ID and sequence number to create the ID. 4 | # The ID should be a 64-bit integer 5 | 6 | import time 7 | import uuid 8 | 9 | class SnowflakeIdentifier: 10 | def __init__(self): 11 | self._machine_id = uuid.getnode() 12 | self._sequence_number = 0 13 | self._last_timestamp = 0 14 | 15 | def get_id(self): 16 | timestamp = int(time.time() * 1000) 17 | if timestamp == self._last_timestamp: 18 | self._sequence_number += 1 19 | else: 20 | self._sequence_number = 0 21 | self._last_timestamp = timestamp 22 | return (timestamp << 22) + (self._machine_id << 10) + self._sequence_number -------------------------------------------------------------------------------- /chapter_4/itam/domain/budget.py: -------------------------------------------------------------------------------- 1 | # create a class called Budget 2 | # with the following attributes: 3 | # - id: int, name: str, department_id: int, amount: float, start_date: datetime, end_date: datetime 4 | # id cannot be nil 5 | # deparment cannot be nil 6 | # amount cannot be nil 7 | # automatically generates special methods for a class that are commonly used for data objects 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class Budget: 14 | id: int 15 | name: str 16 | department_id: int 17 | amount: float 18 | start_date: datetime 19 | end_date: datetime 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.department_id is None: 25 | raise TypeError("Department cannot be None") 26 | if self.amount is None: 27 | raise TypeError("Amount cannot be None") -------------------------------------------------------------------------------- /chapter_5/itam/domain/budget.py: -------------------------------------------------------------------------------- 1 | # create a class called Budget 2 | # with the following attributes: 3 | # - id: int, name: str, department_id: int, amount: float, start_date: datetime, end_date: datetime 4 | # id cannot be nil 5 | # deparment cannot be nil 6 | # amount cannot be nil 7 | # automatically generates special methods for a class that are commonly used for data objects 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class Budget: 14 | id: int 15 | name: str 16 | department_id: int 17 | amount: float 18 | start_date: datetime 19 | end_date: datetime 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.department_id is None: 25 | raise TypeError("Department cannot be None") 26 | if self.amount is None: 27 | raise TypeError("Amount cannot be None") -------------------------------------------------------------------------------- /chapter_6/itam/domain/budget.py: -------------------------------------------------------------------------------- 1 | # create a class called Budget 2 | # with the following attributes: 3 | # - id: int, name: str, department_id: int, amount: float, start_date: datetime, end_date: datetime 4 | # id cannot be nil 5 | # deparment cannot be nil 6 | # amount cannot be nil 7 | # automatically generates special methods for a class that are commonly used for data objects 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class Budget: 14 | id: int 15 | name: str 16 | department_id: int 17 | amount: float 18 | start_date: datetime 19 | end_date: datetime 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.department_id is None: 25 | raise TypeError("Department cannot be None") 26 | if self.amount is None: 27 | raise TypeError("Amount cannot be None") -------------------------------------------------------------------------------- /chapter_7/itam/domain/budget.py: -------------------------------------------------------------------------------- 1 | # create a class called Budget 2 | # with the following attributes: 3 | # - id: int, name: str, department_id: int, amount: float, start_date: datetime, end_date: datetime 4 | # id cannot be nil 5 | # deparment cannot be nil 6 | # amount cannot be nil 7 | # automatically generates special methods for a class that are commonly used for data objects 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class Budget: 14 | id: int 15 | name: str 16 | department_id: int 17 | amount: float 18 | start_date: datetime 19 | end_date: datetime 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.department_id is None: 25 | raise TypeError("Department cannot be None") 26 | if self.amount is None: 27 | raise TypeError("Amount cannot be None") -------------------------------------------------------------------------------- /chapter_4/itam/domain/location.py: -------------------------------------------------------------------------------- 1 | # define the Location entity using Python's built-in dataclass decorator. 2 | # The Location entity has four attributes: id: int, name: str, address: Address, and organization: Organization which is optional. 3 | 4 | from dataclasses import dataclass 5 | from itam.domain.address import Address 6 | from itam.domain.organization import Organization 7 | from typing import Optional 8 | 9 | @dataclass 10 | class Location: 11 | id: int 12 | name: str 13 | address: Address 14 | organization: Optional[Organization] 15 | 16 | def __post_init__(self): 17 | if self.id is None: 18 | raise TypeError("Id cannot be None") 19 | if self.name is None: 20 | raise TypeError("Name cannot be None") 21 | if self.address is None: 22 | raise TypeError("Address cannot be None") 23 | if self.organization is None: 24 | raise TypeError("Organization cannot be None") -------------------------------------------------------------------------------- /chapter_5/data/scripts/load.sql: -------------------------------------------------------------------------------- 1 | # write the postgres command to load data into the database from a csv 2 | # file named assets.csv in the data directory 3 | # the file should have a header row and the columns should have the data types 4 | # id (int), name (varchar), status (varchar), category (varchar), cost (float), useful_life (float), salvage_value (float), funding_details (varchar), depreciation_strategy (varchar) 5 | # the file should be loaded into a table named assets 6 | # the table should be created if it does not exist 7 | # the table should be truncated before loading the data 8 | 9 | create table if not exists assets ( 10 | id int, 11 | name varchar, 12 | status varchar, 13 | category varchar, 14 | cost float, 15 | useful_life float, 16 | salvage_value float, 17 | funding_details varchar, 18 | depreciation_strategy varchar 19 | ); 20 | 21 | psql -d postgres -c "copy assets from '/data/assets.csv' delimiter ',' csv header;" -------------------------------------------------------------------------------- /chapter_6/data/scripts/load.sql: -------------------------------------------------------------------------------- 1 | # write the postgres command to load data into the database from a csv 2 | # file named assets.csv in the data directory 3 | # the file should have a header row and the columns should have the data types 4 | # id (int), name (varchar), status (varchar), category (varchar), cost (float), useful_life (float), salvage_value (float), funding_details (varchar), depreciation_strategy (varchar) 5 | # the file should be loaded into a table named assets 6 | # the table should be created if it does not exist 7 | # the table should be truncated before loading the data 8 | 9 | create table if not exists assets ( 10 | id int, 11 | name varchar, 12 | status varchar, 13 | category varchar, 14 | cost float, 15 | useful_life float, 16 | salvage_value float, 17 | funding_details varchar, 18 | depreciation_strategy varchar 19 | ); 20 | 21 | psql -d postgres -c "copy assets from '/data/assets.csv' delimiter ',' csv header;" -------------------------------------------------------------------------------- /chapter_7/data/scripts/load.sql: -------------------------------------------------------------------------------- 1 | # write the postgres command to load data into the database from a csv 2 | # file named assets.csv in the data directory 3 | # the file should have a header row and the columns should have the data types 4 | # id (int), name (varchar), status (varchar), category (varchar), cost (float), useful_life (float), salvage_value (float), funding_details (varchar), depreciation_strategy (varchar) 5 | # the file should be loaded into a table named assets 6 | # the table should be created if it does not exist 7 | # the table should be truncated before loading the data 8 | 9 | create table if not exists assets ( 10 | id int, 11 | name varchar, 12 | status varchar, 13 | category varchar, 14 | cost float, 15 | useful_life float, 16 | salvage_value float, 17 | funding_details varchar, 18 | depreciation_strategy varchar 19 | ); 20 | 21 | psql -d postgres -c "copy assets from '/data/assets.csv' delimiter ',' csv header;" -------------------------------------------------------------------------------- /chapter_4/itam/domain/warranty.py: -------------------------------------------------------------------------------- 1 | # Define the Warranty entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date 7 | 8 | from datetime import datetime 9 | from dataclasses import dataclass 10 | 11 | 12 | @dataclass 13 | class Warranty: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.name is None: 25 | raise TypeError("Name cannot be None") 26 | if self.description is None: 27 | raise TypeError("Description cannot be None") 28 | if self.start_date is None: 29 | raise TypeError("Start date cannot be None") 30 | if self.end_date is None: 31 | raise TypeError("End date cannot be None") 32 | -------------------------------------------------------------------------------- /chapter_5/itam/domain/warranty.py: -------------------------------------------------------------------------------- 1 | # Define the Warranty entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date 7 | 8 | from datetime import datetime 9 | from dataclasses import dataclass 10 | 11 | 12 | @dataclass 13 | class Warranty: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.name is None: 25 | raise TypeError("Name cannot be None") 26 | if self.description is None: 27 | raise TypeError("Description cannot be None") 28 | if self.start_date is None: 29 | raise TypeError("Start date cannot be None") 30 | if self.end_date is None: 31 | raise TypeError("End date cannot be None") 32 | -------------------------------------------------------------------------------- /chapter_6/itam/domain/warranty.py: -------------------------------------------------------------------------------- 1 | # Define the Warranty entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date 7 | 8 | from datetime import datetime 9 | from dataclasses import dataclass 10 | 11 | 12 | @dataclass 13 | class Warranty: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.name is None: 25 | raise TypeError("Name cannot be None") 26 | if self.description is None: 27 | raise TypeError("Description cannot be None") 28 | if self.start_date is None: 29 | raise TypeError("Start date cannot be None") 30 | if self.end_date is None: 31 | raise TypeError("End date cannot be None") 32 | -------------------------------------------------------------------------------- /chapter_7/itam/domain/warranty.py: -------------------------------------------------------------------------------- 1 | # Define the Warranty entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date 7 | 8 | from datetime import datetime 9 | from dataclasses import dataclass 10 | 11 | 12 | @dataclass 13 | class Warranty: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | 21 | def __post_init__(self): 22 | if self.id is None: 23 | raise TypeError("Id cannot be None") 24 | if self.name is None: 25 | raise TypeError("Name cannot be None") 26 | if self.description is None: 27 | raise TypeError("Description cannot be None") 28 | if self.start_date is None: 29 | raise TypeError("Start date cannot be None") 30 | if self.end_date is None: 31 | raise TypeError("End date cannot be None") 32 | -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/repository/base_repository.py: -------------------------------------------------------------------------------- 1 | # Create an abstract base class called BaseRepository that represents a generic data access layer using the Repository pattern. 2 | # The class should define common methods for CRUD operations such as create, read, update, and delete. 3 | # Make sure to use type hints for the input parameters and return values. 4 | 5 | from abc import ABC, abstractmethod 6 | from typing import List, TypeVar, Generic 7 | 8 | T = TypeVar('T') 9 | 10 | class BaseRepository(ABC, Generic[T]): 11 | @abstractmethod 12 | def create(self, entity: T) -> None: 13 | pass 14 | 15 | @abstractmethod 16 | def read(self, entity_id: int) -> T: 17 | pass 18 | 19 | @abstractmethod 20 | def update(self, entity: T) -> None: 21 | pass 22 | 23 | @abstractmethod 24 | def delete(self, entity_id: int) -> None: 25 | pass 26 | 27 | @abstractmethod 28 | def get_entities(self) -> List[T]: 29 | pass -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/repository/base_repository.py: -------------------------------------------------------------------------------- 1 | # Create an abstract base class called BaseRepository that represents a generic data access layer using the Repository pattern. 2 | # The class should define common methods for CRUD operations such as create, read, update, and delete. 3 | # Make sure to use type hints for the input parameters and return values. 4 | 5 | from abc import ABC, abstractmethod 6 | from typing import List, TypeVar, Generic 7 | 8 | T = TypeVar('T') 9 | 10 | class BaseRepository(ABC, Generic[T]): 11 | @abstractmethod 12 | def create(self, entity: T) -> None: 13 | pass 14 | 15 | @abstractmethod 16 | def read(self, entity_id: int) -> T: 17 | pass 18 | 19 | @abstractmethod 20 | def update(self, entity: T) -> None: 21 | pass 22 | 23 | @abstractmethod 24 | def delete(self, entity_id: int) -> None: 25 | pass 26 | 27 | @abstractmethod 28 | def get_entities(self) -> List[T]: 29 | pass -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/repository/base_repository.py: -------------------------------------------------------------------------------- 1 | # Create an abstract base class called BaseRepository that represents a generic data access layer using the Repository pattern. 2 | # The class should define common methods for CRUD operations such as create, read, update, and delete. 3 | # Make sure to use type hints for the input parameters and return values. 4 | 5 | from abc import ABC, abstractmethod 6 | from typing import List, TypeVar, Generic 7 | 8 | T = TypeVar('T') 9 | 10 | class BaseRepository(ABC, Generic[T]): 11 | @abstractmethod 12 | def create(self, entity: T) -> None: 13 | pass 14 | 15 | @abstractmethod 16 | def read(self, entity_id: int) -> T: 17 | pass 18 | 19 | @abstractmethod 20 | def update(self, entity: T) -> None: 21 | pass 22 | 23 | @abstractmethod 24 | def delete(self, entity_id: int) -> None: 25 | pass 26 | 27 | @abstractmethod 28 | def get_entities(self) -> List[T]: 29 | pass -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/repository/base_repository.py: -------------------------------------------------------------------------------- 1 | # Create an abstract base class called BaseRepository that represents a generic data access layer using the Repository pattern. 2 | # The class should define common methods for CRUD operations such as create, read, update, and delete. 3 | # Make sure to use type hints for the input parameters and return values. 4 | 5 | from abc import ABC, abstractmethod 6 | from typing import List, TypeVar, Generic 7 | 8 | T = TypeVar('T') 9 | 10 | class BaseRepository(ABC, Generic[T]): 11 | @abstractmethod 12 | def create(self, entity: T) -> None: 13 | pass 14 | 15 | @abstractmethod 16 | def read(self, entity_id: int) -> T: 17 | pass 18 | 19 | @abstractmethod 20 | def update(self, entity: T) -> None: 21 | pass 22 | 23 | @abstractmethod 24 | def delete(self, entity_id: int) -> None: 25 | pass 26 | 27 | @abstractmethod 28 | def get_entities(self) -> List[T]: 29 | pass -------------------------------------------------------------------------------- /chapter_4/itam/domain/maintenance_schedule.py: -------------------------------------------------------------------------------- 1 | # Define the MaintenanceSchedule entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date, 7 | # - hardware : Hardware 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class MaintenanceSchedule: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | def __post_init__(self): 21 | if self.id is None: 22 | raise TypeError("Id cannot be None") 23 | if self.name is None: 24 | raise TypeError("Name cannot be None") 25 | if self.description is None: 26 | raise TypeError("Description cannot be None") 27 | if self.start_date is None: 28 | raise TypeError("Start date cannot be None") 29 | if self.end_date is None: 30 | raise TypeError("End date cannot be None") -------------------------------------------------------------------------------- /chapter_5/itam/domain/maintenance_schedule.py: -------------------------------------------------------------------------------- 1 | # Define the MaintenanceSchedule entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date, 7 | # - hardware : Hardware 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class MaintenanceSchedule: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | def __post_init__(self): 21 | if self.id is None: 22 | raise TypeError("Id cannot be None") 23 | if self.name is None: 24 | raise TypeError("Name cannot be None") 25 | if self.description is None: 26 | raise TypeError("Description cannot be None") 27 | if self.start_date is None: 28 | raise TypeError("Start date cannot be None") 29 | if self.end_date is None: 30 | raise TypeError("End date cannot be None") -------------------------------------------------------------------------------- /chapter_6/itam/domain/maintenance_schedule.py: -------------------------------------------------------------------------------- 1 | # Define the MaintenanceSchedule entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date, 7 | # - hardware : Hardware 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class MaintenanceSchedule: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | def __post_init__(self): 21 | if self.id is None: 22 | raise TypeError("Id cannot be None") 23 | if self.name is None: 24 | raise TypeError("Name cannot be None") 25 | if self.description is None: 26 | raise TypeError("Description cannot be None") 27 | if self.start_date is None: 28 | raise TypeError("Start date cannot be None") 29 | if self.end_date is None: 30 | raise TypeError("End date cannot be None") -------------------------------------------------------------------------------- /chapter_7/itam/domain/maintenance_schedule.py: -------------------------------------------------------------------------------- 1 | # Define the MaintenanceSchedule entity. It should have the following attributes: 2 | # - id: int, 3 | # - name: str, 4 | # - description: str, 5 | # - start_date: date, 6 | # - end_date: date, 7 | # - hardware : Hardware 8 | 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | 12 | @dataclass 13 | class MaintenanceSchedule: 14 | id: int 15 | name: str 16 | description: str 17 | start_date: datetime 18 | end_date: datetime 19 | 20 | def __post_init__(self): 21 | if self.id is None: 22 | raise TypeError("Id cannot be None") 23 | if self.name is None: 24 | raise TypeError("Name cannot be None") 25 | if self.description is None: 26 | raise TypeError("Description cannot be None") 27 | if self.start_date is None: 28 | raise TypeError("Start date cannot be None") 29 | if self.end_date is None: 30 | raise TypeError("End date cannot be None") -------------------------------------------------------------------------------- /chapter_2/copilot/asset_manager.py: -------------------------------------------------------------------------------- 1 | # Create a class called AssetManager that will allow us to store and retrieve assets. 2 | 3 | class AssetManager: 4 | def __init__(self): 5 | self.assets = [] 6 | 7 | def add_asset(self, asset): 8 | self.assets.append(asset) 9 | 10 | def get_assets(self): 11 | return self.assets 12 | 13 | def get_asset(self, asset_id): 14 | for asset in self.assets: 15 | if asset.id == asset_id: 16 | return asset 17 | return None 18 | 19 | def update_asset(self, asset_id, asset): 20 | for index, asset in enumerate(self.assets): 21 | if asset.id == asset_id: 22 | self.assets[index] = asset 23 | return True 24 | return False 25 | 26 | def delete_asset(self, asset_id): 27 | for index, asset in enumerate(self.assets): 28 | if asset.id == asset_id: 29 | del self.assets[index] 30 | return True 31 | return False -------------------------------------------------------------------------------- /chapter_4/itam/domain/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the domain module 2 | 3 | from .asset import Asset 4 | from .budget import Budget 5 | from .depreciation_strategy import DepreciationStrategy, StraightLineDepreciationStrategy, DecliningBalanceDepreciationStrategy, DoubleDecliningDepreciationStrategy, NoDepreciationStrategy 6 | from .funding_details import FundingDetails 7 | from .hardware import Hardware 8 | from .location import Location, Address 9 | from .organization import Organization 10 | from .software import Software 11 | from .user import User 12 | from .role import Role 13 | 14 | __all__ = [ 15 | "Asset", 16 | "Budget", 17 | "Software", 18 | "Hardware", 19 | "Department", 20 | "Organization", 21 | "Location", 22 | "Address", 23 | "DepreciationStrategy", 24 | "DecliningBalanceDepreciationStrategy", 25 | "StraightLineDepreciationStrategy", 26 | "DoubleDecliningDepreciationStrategy", 27 | "NoDepreciationStrategy", 28 | "Organization", 29 | "User", 30 | "Role", 31 | "FundingDetails" 32 | ] 33 | -------------------------------------------------------------------------------- /chapter_5/itam/domain/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the domain module 2 | 3 | from .asset import Asset 4 | from .budget import Budget 5 | from .depreciation_strategy import DepreciationStrategy, StraightLineDepreciationStrategy, DecliningBalanceDepreciationStrategy, DoubleDecliningDepreciationStrategy, NoDepreciationStrategy 6 | from .funding_details import FundingDetails 7 | from .hardware import Hardware 8 | from .location import Location, Address 9 | from .organization import Organization 10 | from .software import Software 11 | from .user import User 12 | from .role import Role 13 | 14 | __all__ = [ 15 | "Asset", 16 | "Budget", 17 | "Software", 18 | "Hardware", 19 | "Department", 20 | "Organization", 21 | "Location", 22 | "Address", 23 | "DepreciationStrategy", 24 | "DecliningBalanceDepreciationStrategy", 25 | "StraightLineDepreciationStrategy", 26 | "DoubleDecliningDepreciationStrategy", 27 | "NoDepreciationStrategy", 28 | "Organization", 29 | "User", 30 | "Role", 31 | "FundingDetails" 32 | ] 33 | -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/adapters/asset_rest_adapter.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestAdapter 2 | # It should take an AssetManager as a parameter in its constructor 3 | # It should expose all of the methods in AssetManager 4 | # It should inherit from AssetRestPort 5 | 6 | from itam.domain.asset import Asset 7 | from itam.infrastructure.ports.asset_rest_port import AssetRestPort 8 | from itam.service.asset_manager import AssetManager 9 | 10 | class AssetRestAdapter(AssetRestPort): 11 | def __init__(self, asset_manager: AssetManager): 12 | self._asset_manager = asset_manager 13 | 14 | def read(self, asset_id: int) -> Asset: 15 | return self._asset_manager.read(asset_id) 16 | 17 | def create(self, asset: Asset) -> None: 18 | self._asset_manager.create(asset) 19 | 20 | def update(self, asset: Asset) -> None: 21 | self._asset_manager.update(asset) 22 | 23 | def delete(self, asset_id: int) -> None: 24 | self._asset_manager.delete(asset_id) 25 | 26 | def get_assets(self): 27 | return self._asset_manager.get_assets() 28 | -------------------------------------------------------------------------------- /chapter_6/itam/domain/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the domain module 2 | 3 | from .asset import Asset 4 | from .budget import Budget 5 | from .department import Department 6 | from .depreciation_strategy import DepreciationStrategy, StraightLineDepreciationStrategy, DecliningBalanceDepreciationStrategy, DoubleDecliningDepreciationStrategy, NoDepreciationStrategy 7 | from .funding_details import FundingDetails 8 | from .hardware import Hardware 9 | from .location import Location, Address 10 | from .organization import Organization 11 | from .software import Software 12 | from .user import User 13 | from .role import Role 14 | 15 | __all__ = [ 16 | "Asset", 17 | "Budget", 18 | "Software", 19 | "Hardware", 20 | "Department", 21 | "Organization", 22 | "Location", 23 | "Address", 24 | "DepreciationStrategy", 25 | "DecliningBalanceDepreciationStrategy", 26 | "StraightLineDepreciationStrategy", 27 | "DoubleDecliningDepreciationStrategy", 28 | "NoDepreciationStrategy", 29 | "Organization", 30 | "User", 31 | "Role", 32 | "FundingDetails" 33 | ] 34 | -------------------------------------------------------------------------------- /chapter_7/itam/domain/__init__.py: -------------------------------------------------------------------------------- 1 | # import all of the classes from the domain module 2 | 3 | from .asset import Asset 4 | from .budget import Budget 5 | from .department import Department 6 | from .depreciation_strategy import DepreciationStrategy, StraightLineDepreciationStrategy, DecliningBalanceDepreciationStrategy, DoubleDecliningDepreciationStrategy, NoDepreciationStrategy 7 | from .funding_details import FundingDetails 8 | from .hardware import Hardware 9 | from .location import Location, Address 10 | from .organization import Organization 11 | from .software import Software 12 | from .user import User 13 | from .role import Role 14 | 15 | __all__ = [ 16 | "Asset", 17 | "Budget", 18 | "Software", 19 | "Hardware", 20 | "Department", 21 | "Organization", 22 | "Location", 23 | "Address", 24 | "DepreciationStrategy", 25 | "DecliningBalanceDepreciationStrategy", 26 | "StraightLineDepreciationStrategy", 27 | "DoubleDecliningDepreciationStrategy", 28 | "NoDepreciationStrategy", 29 | "Organization", 30 | "User", 31 | "Role", 32 | "FundingDetails" 33 | ] 34 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/gpt-itam-env/bin/activate.csh: -------------------------------------------------------------------------------- 1 | # This file must be used with "source bin/activate.csh" *from csh*. 2 | # You cannot run it directly. 3 | # Created by Davide Di Blasi . 4 | # Ported to Python 3.3 venv by Andrew Svetlov 5 | 6 | alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' 7 | 8 | # Unset irrelevant variables. 9 | deactivate nondestructive 10 | 11 | setenv VIRTUAL_ENV "/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env" 12 | 13 | set _OLD_VIRTUAL_PATH="$PATH" 14 | setenv PATH "$VIRTUAL_ENV/bin:$PATH" 15 | 16 | 17 | set _OLD_VIRTUAL_PROMPT="$prompt" 18 | 19 | if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then 20 | set prompt = "(gpt-itam-env) $prompt" 21 | setenv VIRTUAL_ENV_PROMPT "(gpt-itam-env) " 22 | endif 23 | 24 | alias pydoc python -m pydoc 25 | 26 | rehash 27 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/gpt-itam-env/bin/activate.csh: -------------------------------------------------------------------------------- 1 | # This file must be used with "source bin/activate.csh" *from csh*. 2 | # You cannot run it directly. 3 | # Created by Davide Di Blasi . 4 | # Ported to Python 3.3 venv by Andrew Svetlov 5 | 6 | alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' 7 | 8 | # Unset irrelevant variables. 9 | deactivate nondestructive 10 | 11 | setenv VIRTUAL_ENV "/Users/nbcrocker/Desktop/ai_guided_dev/chpt02/chatgpt/gpt-itam-env" 12 | 13 | set _OLD_VIRTUAL_PATH="$PATH" 14 | setenv PATH "$VIRTUAL_ENV/bin:$PATH" 15 | 16 | 17 | set _OLD_VIRTUAL_PROMPT="$prompt" 18 | 19 | if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then 20 | set prompt = "(gpt-itam-env) $prompt" 21 | setenv VIRTUAL_ENV_PROMPT "(gpt-itam-env) " 22 | endif 23 | 24 | alias pydoc python -m pydoc 25 | 26 | rehash 27 | -------------------------------------------------------------------------------- /chapter_4/itam/domain/funding_details.py: -------------------------------------------------------------------------------- 1 | # Define a class called FundingDetails 2 | # It should have the following attributes: 3 | # - depreciation_strategy: DepreciationStrategy, 4 | # - depreciation_rate: float 5 | # - department_allocations: Dict[Department, float] 6 | # The attributes cannot be None and cannot be modified after construction 7 | # However, we should be able to access the attributes using methods 8 | 9 | from dataclasses import dataclass 10 | from itam.domain.depreciation_strategy import DepreciationStrategy 11 | from itam.domain.asset import Asset 12 | from itam.domain.department import Department 13 | from typing import Dict 14 | 15 | @dataclass 16 | class FundingDetails: 17 | asset: Asset 18 | depreciation_strategy: DepreciationStrategy 19 | depreciation_rate: float 20 | department_allocations: Dict[Department, float] 21 | 22 | def get_depreciation_strategy(self): 23 | return self.depreciation_strategy 24 | 25 | def get_depreciation_rate(self): 26 | return self.depreciation_rate 27 | 28 | def get_department_allocations(self): 29 | return self.department_allocations -------------------------------------------------------------------------------- /chapter_5/itam/domain/funding_details.py: -------------------------------------------------------------------------------- 1 | # Define a class called FundingDetails 2 | # It should have the following attributes: 3 | # - depreciation_strategy: DepreciationStrategy, 4 | # - depreciation_rate: float 5 | # - department_allocations: Dict[Department, float] 6 | # The attributes cannot be None and cannot be modified after construction 7 | # However, we should be able to access the attributes using methods 8 | 9 | from dataclasses import dataclass 10 | from itam.domain.depreciation_strategy import DepreciationStrategy 11 | from itam.domain.asset import Asset 12 | from itam.domain.department import Department 13 | from typing import Dict 14 | 15 | @dataclass 16 | class FundingDetails: 17 | asset: Asset 18 | depreciation_strategy: DepreciationStrategy 19 | depreciation_rate: float 20 | department_allocations: Dict[Department, float] 21 | 22 | def get_depreciation_strategy(self): 23 | return self.depreciation_strategy 24 | 25 | def get_depreciation_rate(self): 26 | return self.depreciation_rate 27 | 28 | def get_department_allocations(self): 29 | return self.department_allocations -------------------------------------------------------------------------------- /chapter_4/itam/domain/user.py: -------------------------------------------------------------------------------- 1 | # Create a class called User. 2 | # The User entity has the following attributes: 3 | # - username: str, 4 | # - password: str, 5 | # - roles: List[Role] 6 | # none of the attributes can be None 7 | # The User entity should have two methods: has_role() and has_role_by_name(). 8 | 9 | from dataclasses import dataclass 10 | from typing import List 11 | from itam.domain.role import Role 12 | 13 | @dataclass 14 | class User: 15 | username: str 16 | password: str 17 | roles: List[Role] 18 | 19 | def __post_init__(self): 20 | if self.username is None: 21 | raise TypeError("Username cannot be None") 22 | if self.password is None: 23 | raise TypeError("Password cannot be None") 24 | if self.roles is None: 25 | raise TypeError("Roles cannot be None") 26 | 27 | def has_role(self, role: Role) -> bool: 28 | return role in self.roles 29 | 30 | def has_role_by_name(self, role_name: str) -> bool: 31 | for role in self.roles: 32 | if role.name == role_name: 33 | return True 34 | return False -------------------------------------------------------------------------------- /chapter_5/itam/domain/user.py: -------------------------------------------------------------------------------- 1 | # Create a class called User. 2 | # The User entity has the following attributes: 3 | # - username: str, 4 | # - password: str, 5 | # - roles: List[Role] 6 | # none of the attributes can be None 7 | # The User entity should have two methods: has_role() and has_role_by_name(). 8 | 9 | from dataclasses import dataclass 10 | from typing import List 11 | from itam.domain.role import Role 12 | 13 | @dataclass 14 | class User: 15 | username: str 16 | password: str 17 | roles: List[Role] 18 | 19 | def __post_init__(self): 20 | if self.username is None: 21 | raise TypeError("Username cannot be None") 22 | if self.password is None: 23 | raise TypeError("Password cannot be None") 24 | if self.roles is None: 25 | raise TypeError("Roles cannot be None") 26 | 27 | def has_role(self, role: Role) -> bool: 28 | return role in self.roles 29 | 30 | def has_role_by_name(self, role_name: str) -> bool: 31 | for role in self.roles: 32 | if role.name == role_name: 33 | return True 34 | return False -------------------------------------------------------------------------------- /chapter_6/itam/domain/user.py: -------------------------------------------------------------------------------- 1 | # Create a class called User. 2 | # The User entity has the following attributes: 3 | # - username: str, 4 | # - password: str, 5 | # - roles: List[Role] 6 | # none of the attributes can be None 7 | # The User entity should have two methods: has_role() and has_role_by_name(). 8 | 9 | from dataclasses import dataclass 10 | from typing import List 11 | from itam.domain.role import Role 12 | 13 | @dataclass 14 | class User: 15 | username: str 16 | password: str 17 | roles: List[Role] 18 | 19 | def __post_init__(self): 20 | if self.username is None: 21 | raise TypeError("Username cannot be None") 22 | if self.password is None: 23 | raise TypeError("Password cannot be None") 24 | if self.roles is None: 25 | raise TypeError("Roles cannot be None") 26 | 27 | def has_role(self, role: Role) -> bool: 28 | return role in self.roles 29 | 30 | def has_role_by_name(self, role_name: str) -> bool: 31 | for role in self.roles: 32 | if role.name == role_name: 33 | return True 34 | return False -------------------------------------------------------------------------------- /chapter_7/itam/domain/user.py: -------------------------------------------------------------------------------- 1 | # Create a class called User. 2 | # The User entity has the following attributes: 3 | # - username: str, 4 | # - password: str, 5 | # - roles: List[Role] 6 | # none of the attributes can be None 7 | # The User entity should have two methods: has_role() and has_role_by_name(). 8 | 9 | from dataclasses import dataclass 10 | from typing import List 11 | from itam.domain.role import Role 12 | 13 | @dataclass 14 | class User: 15 | username: str 16 | password: str 17 | roles: List[Role] 18 | 19 | def __post_init__(self): 20 | if self.username is None: 21 | raise TypeError("Username cannot be None") 22 | if self.password is None: 23 | raise TypeError("Password cannot be None") 24 | if self.roles is None: 25 | raise TypeError("Roles cannot be None") 26 | 27 | def has_role(self, role: Role) -> bool: 28 | return role in self.roles 29 | 30 | def has_role_by_name(self, role_name: str) -> bool: 31 | for role in self.roles: 32 | if role.name == role_name: 33 | return True 34 | return False -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/adapters/asset_rest_adapter.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestAdapter 2 | # It should take an AssetManager as a parameter in its constructor 3 | # It should expose all of the methods in AssetManager 4 | # It should inherit from AssetRestPort 5 | 6 | from itam.domain.asset import Asset 7 | from itam.infrastructure.ports.asset_rest_port import AssetRestPort 8 | from itam.service.asset_manager import AssetManager 9 | from typing import List 10 | 11 | class AssetRestAdapter(AssetRestPort): 12 | def __init__(self, asset_manager: AssetManager): 13 | self._asset_manager = asset_manager 14 | 15 | def read(self, asset_id: int) -> Asset: 16 | return self._asset_manager.read(asset_id) 17 | 18 | def create(self, asset: Asset) -> None: 19 | self._asset_manager.create(asset) 20 | 21 | def update(self, asset: Asset) -> None: 22 | self._asset_manager.update(asset) 23 | 24 | def delete(self, asset_id: int) -> None: 25 | self._asset_manager.delete(asset_id) 26 | 27 | def get_assets(self) -> List[Asset]: 28 | return self._asset_manager.get_assets() 29 | -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/adapters/asset_rest_adapter.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestAdapter 2 | # It should take an AssetManager as a parameter in its constructor 3 | # It should expose all of the methods in AssetManager 4 | # It should inherit from AssetRestPort 5 | 6 | from itam.domain.asset import Asset 7 | from itam.infrastructure.ports.asset_rest_port import AssetRestPort 8 | from itam.service.asset_manager import AssetManager 9 | from typing import List 10 | 11 | class AssetRestAdapter(AssetRestPort): 12 | def __init__(self, asset_manager: AssetManager): 13 | self._asset_manager = asset_manager 14 | 15 | def read(self, asset_id: int) -> Asset: 16 | return self._asset_manager.read(asset_id) 17 | 18 | def create(self, asset: Asset) -> None: 19 | self._asset_manager.create(asset) 20 | 21 | def update(self, asset: Asset) -> None: 22 | self._asset_manager.update(asset) 23 | 24 | def delete(self, asset_id: int) -> None: 25 | self._asset_manager.delete(asset_id) 26 | 27 | def get_assets(self) -> List[Asset]: 28 | return self._asset_manager.get_assets() 29 | -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/adapters/asset_rest_adapter.py: -------------------------------------------------------------------------------- 1 | # Define an interface called AssetRestAdapter 2 | # It should take an AssetManager as a parameter in its constructor 3 | # It should expose all of the methods in AssetManager 4 | # It should inherit from AssetRestPort 5 | 6 | from itam.domain.asset import Asset 7 | from itam.infrastructure.ports.asset_rest_port import AssetRestPort 8 | from itam.service.asset_manager import AssetManager 9 | from typing import List 10 | 11 | class AssetRestAdapter(AssetRestPort): 12 | def __init__(self, asset_manager: AssetManager): 13 | self._asset_manager = asset_manager 14 | 15 | def read(self, asset_id: int) -> Asset: 16 | return self._asset_manager.read(asset_id) 17 | 18 | def create(self, asset: Asset) -> None: 19 | self._asset_manager.create(asset) 20 | 21 | def update(self, asset: Asset) -> None: 22 | self._asset_manager.update(asset) 23 | 24 | def delete(self, asset_id: int) -> None: 25 | self._asset_manager.delete(asset_id) 26 | 27 | def get_assets(self) -> List[Asset]: 28 | return self._asset_manager.get_assets() 29 | -------------------------------------------------------------------------------- /chapter_5/README.md: -------------------------------------------------------------------------------- 1 | # The AI-Assisted Developer Chapter 5 2 | 3 | {"asset_id": 1, "latitude": 41.8781, "longitude": -87.6298, "timestamp": "2022-01-01T00:00:00Z"} 4 | {"asset_id": 1, "latitude": 41.9000, "longitude": -87.6244, "timestamp": "2022-01-01T00:10:00Z"} 5 | {"asset_id": 1, "latitude": 41.8676, "longitude": -87.6270, "timestamp": "2022-01-01T00:20:00Z"} 6 | {"asset_id": 1, "latitude": 41.8788, "longitude": -87.6359, "timestamp": "2022-01-01T00:30:00Z"} 7 | {"asset_id": 1, "latitude": 41.8740, "longitude": -87.6298, "timestamp": "2022-01-01T00:40:00Z"} 8 | {"asset_id": 1, "latitude": 41.8800, "longitude": -87.6300, "timestamp": "2022-01-01T00:50:00Z"} 9 | {"asset_id": 1, "latitude": 41.8775, "longitude": -87.6244, "timestamp": "2022-01-01T01:00:00Z"} 10 | {"asset_id": 1, "latitude": 41.8745, "longitude": -87.6328, "timestamp": "2022-01-01T01:10:00Z"} 11 | {"asset_id": 1, "latitude": 41.8825, "longitude": -87.6298, "timestamp": "2022-01-01T01:20:00Z"} 12 | {"asset_id": 1, "latitude": 41.8800, "longitude": -87.6250, "timestamp": "2022-01-01T01:30:00Z"} 13 | 14 | {"asset_id": 1, "latitude": 40.7128, "longitude": -74.0060, "timestamp": "2022-01-01T13:30:00Z"} -------------------------------------------------------------------------------- /chapter_6/README.md: -------------------------------------------------------------------------------- 1 | # The AI-Assisted Developer Chapter 5 2 | 3 | {"asset_id": 1, "latitude": 41.8781, "longitude": -87.6298, "timestamp": "2022-01-01T00:00:00Z"} 4 | {"asset_id": 1, "latitude": 41.9000, "longitude": -87.6244, "timestamp": "2022-01-01T00:10:00Z"} 5 | {"asset_id": 1, "latitude": 41.8676, "longitude": -87.6270, "timestamp": "2022-01-01T00:20:00Z"} 6 | {"asset_id": 1, "latitude": 41.8788, "longitude": -87.6359, "timestamp": "2022-01-01T00:30:00Z"} 7 | {"asset_id": 1, "latitude": 41.8740, "longitude": -87.6298, "timestamp": "2022-01-01T00:40:00Z"} 8 | {"asset_id": 1, "latitude": 41.8800, "longitude": -87.6300, "timestamp": "2022-01-01T00:50:00Z"} 9 | {"asset_id": 1, "latitude": 41.8775, "longitude": -87.6244, "timestamp": "2022-01-01T01:00:00Z"} 10 | {"asset_id": 1, "latitude": 41.8745, "longitude": -87.6328, "timestamp": "2022-01-01T01:10:00Z"} 11 | {"asset_id": 1, "latitude": 41.8825, "longitude": -87.6298, "timestamp": "2022-01-01T01:20:00Z"} 12 | {"asset_id": 1, "latitude": 41.8800, "longitude": -87.6250, "timestamp": "2022-01-01T01:30:00Z"} 13 | 14 | {"asset_id": 1, "latitude": 40.7128, "longitude": -74.0060, "timestamp": "2022-01-01T13:30:00Z"} 15 | 16 | -------------------------------------------------------------------------------- /chapter_4/itam/visitor/department_visitor.py: -------------------------------------------------------------------------------- 1 | # define an interface called class DepartmentVisitor with the following methods: 2 | # +visit(self, asset: Asset) -> None 3 | # Additionally, define a class called class DepartmentStatisticsVisitor that implements the interface DepartmentVisitor 4 | 5 | from abc import ABC, abstractmethod 6 | from itam.domain.asset import Asset 7 | 8 | class DepartmentVisitor(ABC): 9 | @abstractmethod 10 | def visit(self, asset: Asset) -> None: 11 | pass 12 | 13 | class DepartmentStatisticsVisitor(DepartmentVisitor): 14 | def __init__(self): 15 | self._total_cost = 0 16 | self._total_depreciation = 0 17 | self._total_allocation = 0 18 | 19 | def visit(self, asset: Asset) -> None: 20 | self._total_cost += asset.get_cost() 21 | self._total_depreciation += asset.get_depreciation() 22 | self._total_allocation += asset.get_allocation() 23 | 24 | def get_total_cost(self): 25 | return self._total_cost 26 | 27 | def get_total_depreciation(self): 28 | return self._total_depreciation 29 | 30 | def get_total_allocation(self): 31 | return self._total_allocation -------------------------------------------------------------------------------- /chapter_5/itam/visitor/department_visitor.py: -------------------------------------------------------------------------------- 1 | # define an interface called class DepartmentVisitor with the following methods: 2 | # +visit(self, asset: Asset) -> None 3 | # Additionally, define a class called class DepartmentStatisticsVisitor that implements the interface DepartmentVisitor 4 | 5 | from abc import ABC, abstractmethod 6 | from itam.domain.asset import Asset 7 | 8 | class DepartmentVisitor(ABC): 9 | @abstractmethod 10 | def visit(self, asset: Asset) -> None: 11 | pass 12 | 13 | class DepartmentStatisticsVisitor(DepartmentVisitor): 14 | def __init__(self): 15 | self._total_cost = 0 16 | self._total_depreciation = 0 17 | self._total_allocation = 0 18 | 19 | def visit(self, asset: Asset) -> None: 20 | self._total_cost += asset.get_cost() 21 | self._total_depreciation += asset.get_depreciation() 22 | self._total_allocation += asset.get_allocation() 23 | 24 | def get_total_cost(self): 25 | return self._total_cost 26 | 27 | def get_total_depreciation(self): 28 | return self._total_depreciation 29 | 30 | def get_total_allocation(self): 31 | return self._total_allocation -------------------------------------------------------------------------------- /chapter_6/itam/domain/funding_details.py: -------------------------------------------------------------------------------- 1 | # Define a class called FundingDetails 2 | # It should have the following attributes: 3 | # - depreciation_strategy: DepreciationStrategy, 4 | # - depreciation_rate: float 5 | # - department_allocations: Dict[Department, float] 6 | # The attributes cannot be None and cannot be modified after construction 7 | # However, we should be able to access the attributes using methods 8 | 9 | from dataclasses import dataclass 10 | from itam.domain.depreciation_strategy import DepreciationStrategy 11 | from itam.domain.department import Department 12 | from typing import Dict 13 | 14 | 15 | @dataclass 16 | class FundingDetails: 17 | depreciation_rate: float 18 | department_allocations: Dict[Department, float] 19 | depreciation_strategy: DepreciationStrategy or 'itam.domain.depreciation_strategy.DepreciationStrategy' 20 | asset: None or 'itam.domain.asset.Asset' 21 | 22 | def get_depreciation_rate(self): 23 | return self.depreciation_rate 24 | 25 | def get_department_allocations(self): 26 | return self.department_allocations 27 | 28 | def get_depreciation_strategy(self): 29 | return self.depreciation_strategy 30 | 31 | def get_asset(self): 32 | return self.asset 33 | -------------------------------------------------------------------------------- /chapter_7/itam/domain/funding_details.py: -------------------------------------------------------------------------------- 1 | # Define a class called FundingDetails 2 | # It should have the following attributes: 3 | # - depreciation_strategy: DepreciationStrategy, 4 | # - depreciation_rate: float 5 | # - department_allocations: Dict[Department, float] 6 | # The attributes cannot be None and cannot be modified after construction 7 | # However, we should be able to access the attributes using methods 8 | 9 | from dataclasses import dataclass 10 | from itam.domain.depreciation_strategy import DepreciationStrategy 11 | from itam.domain.department import Department 12 | from typing import Dict 13 | 14 | 15 | @dataclass 16 | class FundingDetails: 17 | depreciation_rate: float 18 | department_allocations: Dict[Department, float] 19 | depreciation_strategy: DepreciationStrategy or 'itam.domain.depreciation_strategy.DepreciationStrategy' 20 | asset: None or 'itam.domain.asset.Asset' 21 | 22 | def get_depreciation_rate(self): 23 | return self.depreciation_rate 24 | 25 | def get_department_allocations(self): 26 | return self.department_allocations 27 | 28 | def get_depreciation_strategy(self): 29 | return self.depreciation_strategy 30 | 31 | def get_asset(self): 32 | return self.asset 33 | -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/database/database_connection.py: -------------------------------------------------------------------------------- 1 | # Create a Python class called DatabaseConnection that uses the Singleton pattern to manage a single database connection to a PostgreSQL database using SQLAlchemy. 2 | # The class should read the database username, password, and connection string from environment variables 3 | # The environment variables should be named: DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, and DB_NAME 4 | 5 | from sqlalchemy import create_engine 6 | from sqlalchemy.orm import sessionmaker 7 | import os 8 | 9 | class DatabaseConnection: 10 | __instance = None 11 | @staticmethod 12 | def get_instance(): 13 | if DatabaseConnection.__instance == None: 14 | DatabaseConnection() 15 | return DatabaseConnection.__instance 16 | 17 | def __init__(self): 18 | if DatabaseConnection.__instance != None: 19 | raise Exception("This class is a singleton!") 20 | else: 21 | DatabaseConnection.__instance = self 22 | self.engine = create_engine(f"postgresql://{os.environ['DB_USERNAME']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ['DB_PORT']}/{os.environ['DB_NAME']}") 23 | self.Session = sessionmaker(bind=self.engine) 24 | 25 | def get_session(self): 26 | return self.Session() -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/asset.Flask.py: -------------------------------------------------------------------------------- 1 | class Asset: 2 | def __init__(self, asset_id, asset_type, manufacturer, model, purchase_date, warranty_end_date, location): 3 | self.asset_id = asset_id 4 | self.asset_type = asset_type 5 | self.manufacturer = manufacturer 6 | self.model = model 7 | self.purchase_date = purchase_date 8 | self.warranty_end_date = warranty_end_date 9 | self.location = location 10 | self.assigned_to = None 11 | self.status = 'Available' 12 | 13 | def assign_to_user(self, user): 14 | self.assigned_to = user 15 | self.status = 'Assigned' 16 | 17 | def unassign(self): 18 | self.assigned_to = None 19 | self.status = 'Available' 20 | 21 | def get_details(self): 22 | details = f"Asset ID: {self.asset_id}\n" 23 | details += f"Type: {self.asset_type}\n" 24 | details += f"Manufacturer: {self.manufacturer}\n" 25 | details += f"Model: {self.model}\n" 26 | details += f"Purchase Date: {self.purchase_date}\n" 27 | details += f"Warranty End Date: {self.warranty_end_date}\n" 28 | details += f"Location: {self.location}\n" 29 | details += f"Assigned To: {self.assigned_to}\n" 30 | details += f"Status: {self.status}\n" 31 | return details 32 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/asset.Flask.py: -------------------------------------------------------------------------------- 1 | class Asset: 2 | def __init__(self, asset_id, asset_type, manufacturer, model, purchase_date, warranty_end_date, location): 3 | self.asset_id = asset_id 4 | self.asset_type = asset_type 5 | self.manufacturer = manufacturer 6 | self.model = model 7 | self.purchase_date = purchase_date 8 | self.warranty_end_date = warranty_end_date 9 | self.location = location 10 | self.assigned_to = None 11 | self.status = 'Available' 12 | 13 | def assign_to_user(self, user): 14 | self.assigned_to = user 15 | self.status = 'Assigned' 16 | 17 | def unassign(self): 18 | self.assigned_to = None 19 | self.status = 'Available' 20 | 21 | def get_details(self): 22 | details = f"Asset ID: {self.asset_id}\n" 23 | details += f"Type: {self.asset_type}\n" 24 | details += f"Manufacturer: {self.manufacturer}\n" 25 | details += f"Model: {self.model}\n" 26 | details += f"Purchase Date: {self.purchase_date}\n" 27 | details += f"Warranty End Date: {self.warranty_end_date}\n" 28 | details += f"Location: {self.location}\n" 29 | details += f"Assigned To: {self.assigned_to}\n" 30 | details += f"Status: {self.status}\n" 31 | return details 32 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/asset_manager.Flask.py: -------------------------------------------------------------------------------- 1 | class AssetManager: 2 | def __init__(self): 3 | self.assets = [] 4 | 5 | def add_asset(self, asset): 6 | self.assets.append(asset) 7 | 8 | def remove_asset(self, asset_id): 9 | for asset in self.assets: 10 | if asset.asset_id == asset_id: 11 | self.assets.remove(asset) 12 | return True 13 | return False 14 | 15 | def get_asset_by_id(self, asset_id): 16 | for asset in self.assets: 17 | if asset.asset_id == asset_id: 18 | return asset 19 | return None 20 | 21 | def assign_asset(self, asset_id, user): 22 | asset = self.get_asset_by_id(asset_id) 23 | if asset and asset.status == 'Available': 24 | asset.assign_to_user(user) 25 | return True 26 | return False 27 | 28 | def unassign_asset(self, asset_id): 29 | asset = self.get_asset_by_id(asset_id) 30 | if asset and asset.status == 'Assigned': 31 | asset.unassign() 32 | return True 33 | return False 34 | 35 | def get_available_assets(self): 36 | return [asset for asset in self.assets if asset.status == 'Available'] 37 | 38 | def get_assigned_assets(self): 39 | return [asset for asset in self.assets if asset.status == 'Assigned'] 40 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/asset_manager.Flask.py: -------------------------------------------------------------------------------- 1 | class AssetManager: 2 | def __init__(self): 3 | self.assets = [] 4 | 5 | def add_asset(self, asset): 6 | self.assets.append(asset) 7 | 8 | def remove_asset(self, asset_id): 9 | for asset in self.assets: 10 | if asset.asset_id == asset_id: 11 | self.assets.remove(asset) 12 | return True 13 | return False 14 | 15 | def get_asset_by_id(self, asset_id): 16 | for asset in self.assets: 17 | if asset.asset_id == asset_id: 18 | return asset 19 | return None 20 | 21 | def assign_asset(self, asset_id, user): 22 | asset = self.get_asset_by_id(asset_id) 23 | if asset and asset.status == 'Available': 24 | asset.assign_to_user(user) 25 | return True 26 | return False 27 | 28 | def unassign_asset(self, asset_id): 29 | asset = self.get_asset_by_id(asset_id) 30 | if asset and asset.status == 'Assigned': 31 | asset.unassign() 32 | return True 33 | return False 34 | 35 | def get_available_assets(self): 36 | return [asset for asset in self.assets if asset.status == 'Available'] 37 | 38 | def get_assigned_assets(self): 39 | return [asset for asset in self.assets if asset.status == 'Assigned'] 40 | -------------------------------------------------------------------------------- /chapter_2/copilot/app.py: -------------------------------------------------------------------------------- 1 | # Create a FastAPI app that allows CRUD operations on the Asset class. 2 | from fastapi import FastAPI 3 | from fastapi.responses import JSONResponse 4 | from pydantic import BaseModel 5 | from typing import List, Optional 6 | from asset import Asset 7 | from asset_manager import AssetManager 8 | 9 | app = FastAPI() 10 | asset_manager = AssetManager() 11 | 12 | class AssetIn(BaseModel): 13 | asset_id: str 14 | asset_type: str 15 | manufacturer: str 16 | model: str 17 | purchase_date: str 18 | warranty_end_date: str 19 | location: str 20 | 21 | class AssetOut(BaseModel): 22 | asset_id: str 23 | asset_type: str 24 | manufacturer: str 25 | model: str 26 | purchase_date: str 27 | warranty_end_date: str 28 | location: str 29 | assigned_to: Optional[str] 30 | status: str 31 | 32 | @app.get("/assets/", response_model=List[AssetOut]) 33 | async def get_assets(): 34 | assets = asset_manager.get_assets() 35 | return JSONResponse(content=[asset.to_dict() for asset in assets]) 36 | 37 | 38 | @app.post("/assets/") 39 | async def add_asset(asset: AssetIn): 40 | new_asset = Asset(asset.asset_id, asset.asset_type, asset.manufacturer, asset.model, asset.purchase_date, asset.warranty_end_date, asset.location) 41 | asset_manager.add_asset(new_asset) 42 | return {"message": "Asset added successfully"} -------------------------------------------------------------------------------- /chapter_4/main.py: -------------------------------------------------------------------------------- 1 | # Importing the necessary modules and packages 2 | # Instantiating the necessary objects and components, such as the FastAPI application and database connection 3 | # Configuring the application settings and environment variables 4 | # Mounting the HTTP controllers and endpoints to the FastAPI application 5 | # Starting the server and running the application 6 | 7 | from fastapi import FastAPI 8 | from itam.infrastructure.api.asset_controller import AssetController 9 | #from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository 10 | from itam.infrastructure.repository.sqlalchemy_asset_repository import SQLAlchemyAssetRepository 11 | from itam.infrastructure.database.database_connection import DatabaseConnection 12 | from itam.service.asset_manager import AssetManager 13 | from itam.infrastructure.adapters.asset_rest_adapter import AssetRestAdapter 14 | import uvicorn 15 | 16 | app = FastAPI() 17 | session = DatabaseConnection().get_session() 18 | #repository = InMemoryAssetRepository() 19 | repository = SQLAlchemyAssetRepository(session) 20 | asset_manager = AssetManager(repository) 21 | asset_rest_adapter = AssetRestAdapter(asset_manager) 22 | asset_controller = AssetController(asset_rest_adapter) 23 | app.include_router(asset_controller.get_router()) 24 | 25 | if __name__ == '__main__': 26 | uvicorn.run(app, host='0.0.0.0', port=8000) 27 | -------------------------------------------------------------------------------- /chapter_4/itam/service/asset_manager.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetManager 2 | # with CRUD operations for Asset 3 | # and a method to notify observers whenever an asset is created, updated or deleted 4 | # The AssetManager should accpet an instance of the BaseRepository[Asset] for data access and CRUD operations on Asset objects. 5 | # Implement methods for creating, reading, updating, and deleting assets using the AssetRepository instance. 6 | # Please include type hints for the input parameters and return values. 7 | # The methods should be named create, read, update, get_assets, and delete. 8 | 9 | from itam.domain.asset import Asset 10 | from itam.infrastructure.repository.base_repository import BaseRepository 11 | 12 | class AssetManager: 13 | def __init__(self, base_repository: BaseRepository[Asset]): 14 | self._repository = base_repository 15 | 16 | def create(self, asset: Asset) -> Asset: 17 | self._repository.create(asset) 18 | return asset 19 | 20 | def read(self, asset_id: int) -> Asset: 21 | return self._repository.read(asset_id) 22 | 23 | def update(self, asset: Asset) -> Asset: 24 | self._repository.update(asset) 25 | return asset 26 | 27 | def get_assets(self) -> list[Asset]: 28 | return self._repository.get_entities() 29 | 30 | def delete(self, asset_id: int) -> None: 31 | self._repository.delete(asset_id) -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/repository/sqlalchemy_asset_repository.py: -------------------------------------------------------------------------------- 1 | # Define a class called SQLAlchemyAssetRepository that implements the AssetRepository interface for data access using SQLAlchemy. 2 | # The class should handle the CRUD operations (create, read, update, and delete) for assets, storing and retrieving them in a PostgreSQL database using SQLAlchemy. 3 | 4 | from itam.domain.asset import Asset 5 | from itam.infrastructure.repository.base_repository import BaseRepository 6 | from sqlalchemy.orm import Session 7 | 8 | class SQLAlchemyAssetRepository(BaseRepository[Asset]): 9 | def __init__(self, session: Session): 10 | self._session = session 11 | 12 | def create(self, asset: Asset) -> Asset: 13 | self._session.add(asset) 14 | self._session.commit() 15 | return asset 16 | 17 | def read(self, asset_id: int) -> Asset: 18 | return self._session.query(Asset).filter(Asset.id == asset_id).first() 19 | 20 | def update(self, asset: Asset) -> Asset: 21 | self._session.query(Asset).filter(Asset.id == asset.id).update(asset) 22 | self._session.commit() 23 | return asset 24 | 25 | def get_assets(self) -> list[Asset]: 26 | return self._session.query(Asset).all() 27 | 28 | def delete(self, asset_id: int) -> None: 29 | self._session.query(Asset).filter(Asset.id == asset_id).delete() 30 | self._session.commit() -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/repository/in_memory_asset_repository.py: -------------------------------------------------------------------------------- 1 | # Define a class called InMemoryAssetRepository that inherits from the BaseRepository abstract class. 2 | # The InMemoryAssetRepository should be specific to managing Asset objects sing an in-memory list to store and update the assets. 3 | # Implement the necessary methods for CRUD operations such as create, read, update, and delete for Asset objects using the in-memory list. 4 | # Make sure to use type hints for the input parameters and return values. 5 | 6 | from itam.infrastructure.repository.base_repository import BaseRepository 7 | from itam.domain.asset import Asset 8 | 9 | class InMemoryAssetRepository(BaseRepository[Asset]): 10 | def __init__(self): 11 | self._assets = [] 12 | 13 | def create(self, asset: Asset) -> None: 14 | self._assets.append(asset) 15 | 16 | def read(self, asset_id: int) -> Asset: 17 | return next((asset for asset in self._assets if asset.id == asset_id), None) 18 | 19 | def update(self, asset: Asset) -> None: 20 | for i in range(len(self._assets)): 21 | if self._assets[i].id == asset.id: 22 | self._assets[i] = asset 23 | break 24 | 25 | def delete(self, asset_id: int) -> None: 26 | self._assets = [asset for asset in self._assets if asset.id != asset_id] 27 | 28 | def get_entities(self) -> list[Asset]: 29 | return self._assets -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/repository/in_memory_asset_repository.py: -------------------------------------------------------------------------------- 1 | # Define a class called InMemoryAssetRepository that inherits from the BaseRepository abstract class. 2 | # The InMemoryAssetRepository should be specific to managing Asset objects sing an in-memory list to store and update the assets. 3 | # Implement the necessary methods for CRUD operations such as create, read, update, and delete for Asset objects using the in-memory list. 4 | # Make sure to use type hints for the input parameters and return values. 5 | 6 | from itam.infrastructure.repository.base_repository import BaseRepository 7 | from itam.domain.asset import Asset 8 | 9 | class InMemoryAssetRepository(BaseRepository[Asset]): 10 | def __init__(self): 11 | self._assets = [] 12 | 13 | def create(self, asset: Asset) -> None: 14 | self._assets.append(asset) 15 | 16 | def read(self, asset_id: int) -> Asset: 17 | return next((asset for asset in self._assets if asset.id == asset_id), None) 18 | 19 | def update(self, asset: Asset) -> None: 20 | for i in range(len(self._assets)): 21 | if self._assets[i].id == asset.id: 22 | self._assets[i] = asset 23 | break 24 | 25 | def delete(self, asset_id: int) -> None: 26 | self._assets = [asset for asset in self._assets if asset.id != asset_id] 27 | 28 | def get_entities(self) -> list[Asset]: 29 | return self._assets -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/repository/in_memory_asset_repository.py: -------------------------------------------------------------------------------- 1 | # Define a class called InMemoryAssetRepository that inherits from the BaseRepository abstract class. 2 | # The InMemoryAssetRepository should be specific to managing Asset objects sing an in-memory list to store and update the assets. 3 | # Implement the necessary methods for CRUD operations such as create, read, update, and delete for Asset objects using the in-memory list. 4 | # Make sure to use type hints for the input parameters and return values. 5 | 6 | from itam.infrastructure.repository.base_repository import BaseRepository 7 | from itam.domain.asset import Asset 8 | 9 | class InMemoryAssetRepository(BaseRepository[Asset]): 10 | def __init__(self): 11 | self._assets = [] 12 | 13 | def create(self, asset: Asset) -> None: 14 | self._assets.append(asset) 15 | 16 | def read(self, asset_id: int) -> Asset: 17 | return next((asset for asset in self._assets if asset.id == asset_id), None) 18 | 19 | def update(self, asset: Asset) -> None: 20 | for i in range(len(self._assets)): 21 | if self._assets[i].id == asset.id: 22 | self._assets[i] = asset 23 | break 24 | 25 | def delete(self, asset_id: int) -> None: 26 | self._assets = [asset for asset in self._assets if asset.id != asset_id] 27 | 28 | def get_entities(self) -> list[Asset]: 29 | return self._assets -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/repository/in_memory_asset_repository.py: -------------------------------------------------------------------------------- 1 | # Define a class called InMemoryAssetRepository that inherits from the BaseRepository abstract class. 2 | # The InMemoryAssetRepository should be specific to managing Asset objects sing an in-memory list to store and update the assets. 3 | # Implement the necessary methods for CRUD operations such as create, read, update, and delete for Asset objects using the in-memory list. 4 | # Make sure to use type hints for the input parameters and return values. 5 | 6 | from itam.infrastructure.repository.base_repository import BaseRepository 7 | from itam.domain.asset import Asset 8 | 9 | class InMemoryAssetRepository(BaseRepository[Asset]): 10 | def __init__(self): 11 | self._assets = [] 12 | 13 | def create(self, asset: Asset) -> None: 14 | self._assets.append(asset) 15 | 16 | def read(self, asset_id: int) -> Asset: 17 | return next((asset for asset in self._assets if asset.id == asset_id), None) 18 | 19 | def update(self, asset: Asset) -> None: 20 | for i in range(len(self._assets)): 21 | if self._assets[i].id == asset.id: 22 | self._assets[i] = asset 23 | break 24 | 25 | def delete(self, asset_id: int) -> None: 26 | self._assets = [asset for asset in self._assets if asset.id != asset_id] 27 | 28 | def get_entities(self) -> list[Asset]: 29 | return self._assets -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/consumers/asset_location_kafka_consumer.py: -------------------------------------------------------------------------------- 1 | from kafka import KafkaConsumer 2 | from itam.domain.events.asset_location_updated import AssetLocationUpdated 3 | import json 4 | import asyncio 5 | 6 | class AssetLocationKafkaConsumer: 7 | def __init__(self, mediator): 8 | self.mediator = mediator 9 | 10 | self.consumer = KafkaConsumer( 11 | 'asset_location', 12 | bootstrap_servers=['localhost:9092'], 13 | enable_auto_commit=True, 14 | group_id='itam-group', 15 | value_deserializer=lambda m: json.loads(m.decode('utf-8')) 16 | ) 17 | 18 | # Define a function to process Kafka messages 19 | async def process_messages_async(self): 20 | for message in self.consumer: 21 | asset_id = message.value['asset_id'] 22 | latitude = message.value['latitude'] 23 | longitude = message.value['longitude'] 24 | timestamp = message.value['timestamp'] 25 | event = AssetLocationUpdated(asset_id, latitude, longitude, timestamp) 26 | self.mediator.publish(event) 27 | 28 | async def start_consumer_async(self): 29 | print('Starting Kafka consumer...') 30 | await self.process_messages_async() 31 | 32 | def start_consumer(self): 33 | loop = asyncio.new_event_loop() 34 | asyncio.set_event_loop(loop) 35 | loop.run_until_complete(self.start_consumer_async()) -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/consumers/asset_location_kafka_consumer.py: -------------------------------------------------------------------------------- 1 | from kafka import KafkaConsumer 2 | from itam.domain.events.asset_location_updated import AssetLocationUpdated 3 | import json 4 | import asyncio 5 | 6 | class AssetLocationKafkaConsumer: 7 | def __init__(self, mediator): 8 | self.mediator = mediator 9 | 10 | self.consumer = KafkaConsumer( 11 | 'asset_location', 12 | bootstrap_servers=['localhost:9092'], 13 | enable_auto_commit=True, 14 | group_id='itam-group', 15 | value_deserializer=lambda m: json.loads(m.decode('utf-8')) 16 | ) 17 | 18 | # Define a function to process Kafka messages 19 | async def process_messages_async(self): 20 | for message in self.consumer: 21 | asset_id = message.value['asset_id'] 22 | latitude = message.value['latitude'] 23 | longitude = message.value['longitude'] 24 | timestamp = message.value['timestamp'] 25 | event = AssetLocationUpdated(asset_id, latitude, longitude, timestamp) 26 | self.mediator.publish(event) 27 | 28 | async def start_consumer_async(self): 29 | print('Starting Kafka consumer...') 30 | await self.process_messages_async() 31 | 32 | def start_consumer(self): 33 | loop = asyncio.new_event_loop() 34 | asyncio.set_event_loop(loop) 35 | loop.run_until_complete(self.start_consumer_async()) -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/consumers/asset_location_kafka_consumer.py: -------------------------------------------------------------------------------- 1 | from kafka import KafkaConsumer 2 | from itam.domain.events.asset_location_updated import AssetLocationUpdated 3 | import json 4 | import asyncio 5 | 6 | class AssetLocationKafkaConsumer: 7 | def __init__(self, mediator): 8 | self.mediator = mediator 9 | 10 | self.consumer = KafkaConsumer( 11 | 'asset_location', 12 | bootstrap_servers=['localhost:9092'], 13 | enable_auto_commit=True, 14 | group_id='itam-group', 15 | value_deserializer=lambda m: json.loads(m.decode('utf-8')) 16 | ) 17 | 18 | # Define a function to process Kafka messages 19 | async def process_messages_async(self): 20 | for message in self.consumer: 21 | asset_id = message.value['asset_id'] 22 | latitude = message.value['latitude'] 23 | longitude = message.value['longitude'] 24 | timestamp = message.value['timestamp'] 25 | event = AssetLocationUpdated(asset_id, latitude, longitude, timestamp) 26 | self.mediator.publish(event) 27 | 28 | async def start_consumer_async(self): 29 | print('Starting Kafka consumer...') 30 | await self.process_messages_async() 31 | 32 | def start_consumer(self): 33 | loop = asyncio.new_event_loop() 34 | asyncio.set_event_loop(loop) 35 | loop.run_until_complete(self.start_consumer_async()) -------------------------------------------------------------------------------- /chapter_5/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | services: 4 | zookeeper: 5 | image: confluentinc/cp-zookeeper:7.3.2 6 | container_name: zookeeper 7 | ports: 8 | - "2181:2181" 9 | environment: 10 | ZOOKEEPER_CLIENT_PORT: 2181 11 | ZOOKEEPER_SERVER_ID: 1 12 | ZOOKEEPER_SERVERS: zoo1:2888:3888 13 | 14 | kafka: 15 | image: confluentinc/cp-kafka:7.3.2 16 | hostname: kafka 17 | container_name: kafka 18 | ports: 19 | - "9092:9092" 20 | - "29092:29092" 21 | - "9999:9999" 22 | environment: 23 | KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:19092,EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092,DOCKER://host.docker.internal:29092 24 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,DOCKER:PLAINTEXT 25 | KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL 26 | KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" 27 | KAFKA_BROKER_ID: 1 28 | KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO" 29 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 30 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 31 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 32 | KAFKA_JMX_PORT: 9999 33 | KAFKA_JMX_HOSTNAME: ${DOCKER_HOST_IP:-127.0.0.1} 34 | KAFKA_AUTHORIZER_CLASS_NAME: kafka.security.authorizer.AclAuthorizer 35 | KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true" 36 | depends_on: 37 | - zookeeper -------------------------------------------------------------------------------- /chapter_6/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | services: 4 | zookeeper: 5 | image: confluentinc/cp-zookeeper:7.3.2 6 | container_name: zookeeper 7 | ports: 8 | - "2181:2181" 9 | environment: 10 | ZOOKEEPER_CLIENT_PORT: 2181 11 | ZOOKEEPER_SERVER_ID: 1 12 | ZOOKEEPER_SERVERS: zoo1:2888:3888 13 | 14 | kafka: 15 | image: confluentinc/cp-kafka:7.3.2 16 | hostname: kafka 17 | container_name: kafka 18 | ports: 19 | - "9092:9092" 20 | - "29092:29092" 21 | - "9999:9999" 22 | environment: 23 | KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:19092,EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092,DOCKER://host.docker.internal:29092 24 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,DOCKER:PLAINTEXT 25 | KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL 26 | KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" 27 | KAFKA_BROKER_ID: 1 28 | KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO" 29 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 30 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 31 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 32 | KAFKA_JMX_PORT: 9999 33 | KAFKA_JMX_HOSTNAME: ${DOCKER_HOST_IP:-127.0.0.1} 34 | KAFKA_AUTHORIZER_CLASS_NAME: kafka.security.authorizer.AclAuthorizer 35 | KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true" 36 | depends_on: 37 | - zookeeper -------------------------------------------------------------------------------- /chapter_7/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | services: 4 | zookeeper: 5 | image: confluentinc/cp-zookeeper:7.3.2 6 | container_name: zookeeper 7 | ports: 8 | - "2181:2181" 9 | environment: 10 | ZOOKEEPER_CLIENT_PORT: 2181 11 | ZOOKEEPER_SERVER_ID: 1 12 | ZOOKEEPER_SERVERS: zoo1:2888:3888 13 | 14 | kafka: 15 | image: confluentinc/cp-kafka:7.3.2 16 | hostname: kafka 17 | container_name: kafka 18 | ports: 19 | - "9092:9092" 20 | - "29092:29092" 21 | - "9999:9999" 22 | environment: 23 | KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:19092,EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092,DOCKER://host.docker.internal:29092 24 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,DOCKER:PLAINTEXT 25 | KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL 26 | KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" 27 | KAFKA_BROKER_ID: 1 28 | KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO" 29 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 30 | KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 31 | KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 32 | KAFKA_JMX_PORT: 9999 33 | KAFKA_JMX_HOSTNAME: ${DOCKER_HOST_IP:-127.0.0.1} 34 | KAFKA_AUTHORIZER_CLASS_NAME: kafka.security.authorizer.AclAuthorizer 35 | KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true" 36 | depends_on: 37 | - zookeeper -------------------------------------------------------------------------------- /chapter_2/code-whisperer/asset.py: -------------------------------------------------------------------------------- 1 | # Create a class named Asset 2 | # Add the following attributes: id, asset_type, manufacturer, model, purchase_date, purchase_price, warranty_end_date, location, and status. 3 | # The class should have a function named get_details returns a string which is the concatenation of all of the attributes. 4 | # The class should have a function named to_dict that returns a dictionary of all of the attributes. 5 | 6 | class Asset(): 7 | def __init__(self, id, asset_type, manufacturer, model, purchase_date, purchase_price, warranty_end_date, location, status): 8 | self.id = id 9 | self.asset_type = asset_type 10 | self.manufacturer = manufacturer 11 | self.model = model 12 | self.purchase_date = purchase_date 13 | self.purchase_price = purchase_price 14 | self.warranty_end_date = warranty_end_date 15 | self.location = location 16 | self.status = status 17 | 18 | def get_details(self): 19 | return f"{self.id}, {self.asset_type}, {self.manufacturer}, {self.model}, {self.purchase_date}, {self.purchase_price}, {self.warranty_end_date}, {self.location}, {self.status}" 20 | 21 | def to_dict(self): 22 | return {"id": self.id, "asset_type": self.asset_type, "manufacturer": self.manufacturer, "model": self.model, "purchase_date": self.purchase_date, "purchase_price": self.purchase_price, "warranty_end_date": self.warranty_end_date, "location": self.location, "status": self.status} -------------------------------------------------------------------------------- /chapter_2/copilot/asset.py: -------------------------------------------------------------------------------- 1 | # Create a class named Asset 2 | # Add the following attributes: 3 | # id, asset_type, manufacturer, model, purchase_date, purchase_price, warranty_end_date, location, and status. 4 | # The class should have a function named get_details returns a string which is the concatenation of all of the attributes. 5 | # The class should have a function named to_dict that returns a dictionary of all of the attributes. 6 | 7 | class Asset: 8 | def __init__(self): 9 | self.id = None 10 | self.asset_type = None 11 | self.manufacturer = None 12 | self.model = None 13 | self.purchase_date = None 14 | self.purchase_price = None 15 | self.warranty_end_date = None 16 | self.location = None 17 | self.status = None 18 | 19 | def get_details(self): 20 | return f"{self.id}, {self.asset_type}, {self.manufacturer}, {self.model}, {self.purchase_date}, {self.purchase_price}, {self.warranty_end_date}, {self.location}, {self.status}" 21 | 22 | def to_dict(self): 23 | return { 24 | "id": self.id, 25 | "asset_type": self.asset_type, 26 | "manufacturer": self.manufacturer, 27 | "model": self.model, 28 | "purchase_date": self.purchase_date, 29 | "purchase_price": self.purchase_price, 30 | "warranty_end_date": self.warranty_end_date, 31 | "location": self.location, 32 | "status": self.status 33 | } -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/database/database_connection.py: -------------------------------------------------------------------------------- 1 | # Create a Python class called DatabaseConnection that uses the Singleton pattern to manage a single database connection to a PostgreSQL database using SQLAlchemy. 2 | # The class should read the database username, password, and connection string from environment variables 3 | # The environment variables should be named: DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, and DB_NAME 4 | 5 | from sqlalchemy import create_engine 6 | from sqlalchemy.orm import sessionmaker 7 | import os 8 | 9 | class DatabaseConnection: 10 | __instance = None 11 | @staticmethod 12 | def get_instance(): 13 | if DatabaseConnection.__instance == None: 14 | DatabaseConnection() 15 | return DatabaseConnection.__instance 16 | 17 | def __init__(self): 18 | if DatabaseConnection.__instance != None: 19 | raise Exception("This class is a singleton!") 20 | else: 21 | DatabaseConnection.__instance = self 22 | self.engine = create_engine(f"postgresql://itam_user:itam_user@localhost:5432/postgres", connect_args={'options': '-csearch_path=itam'}) 23 | #self.engine = create_engine(f"postgresql://{os.environ['DB_USERNAME']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ['DB_PORT']}/{os.environ['DB_NAME']}", connect_args={'options': '-csearch_path={}'.format(os.environ['DB_SCHEMA'])}) 24 | self.Session = sessionmaker(bind=self.engine) 25 | 26 | def get_session(self): 27 | return self.Session() -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/database/database_connection.py: -------------------------------------------------------------------------------- 1 | # Create a Python class called DatabaseConnection that uses the Singleton pattern to manage a single database connection to a PostgreSQL database using SQLAlchemy. 2 | # The class should read the database username, password, and connection string from environment variables 3 | # The environment variables should be named: DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, and DB_NAME 4 | 5 | from sqlalchemy import create_engine 6 | from sqlalchemy.orm import sessionmaker 7 | import os 8 | 9 | class DatabaseConnection: 10 | __instance = None 11 | @staticmethod 12 | def get_instance(): 13 | if DatabaseConnection.__instance == None: 14 | DatabaseConnection() 15 | return DatabaseConnection.__instance 16 | 17 | def __init__(self): 18 | if DatabaseConnection.__instance != None: 19 | raise Exception("This class is a singleton!") 20 | else: 21 | DatabaseConnection.__instance = self 22 | self.engine = create_engine(f"postgresql://itam_user:itam_user@localhost:5432/postgres", connect_args={'options': '-csearch_path=itam'}) 23 | #self.engine = create_engine(f"postgresql://{os.environ['DB_USERNAME']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ['DB_PORT']}/{os.environ['DB_NAME']}", connect_args={'options': '-csearch_path={}'.format(os.environ['DB_SCHEMA'])}) 24 | self.Session = sessionmaker(bind=self.engine) 25 | 26 | def get_session(self): 27 | return self.Session() -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/database/database_connection.py: -------------------------------------------------------------------------------- 1 | # Create a Python class called DatabaseConnection that uses the Singleton pattern to manage a single database connection to a PostgreSQL database using SQLAlchemy. 2 | # The class should read the database username, password, and connection string from environment variables 3 | # The environment variables should be named: DB_USERNAME, DB_PASSWORD, DB_HOST, DB_PORT, and DB_NAME 4 | 5 | from sqlalchemy import create_engine 6 | from sqlalchemy.orm import sessionmaker 7 | import os 8 | 9 | class DatabaseConnection: 10 | __instance = None 11 | @staticmethod 12 | def get_instance(): 13 | if DatabaseConnection.__instance == None: 14 | DatabaseConnection() 15 | return DatabaseConnection.__instance 16 | 17 | def __init__(self): 18 | if DatabaseConnection.__instance != None: 19 | raise Exception("This class is a singleton!") 20 | else: 21 | DatabaseConnection.__instance = self 22 | self.engine = create_engine(f"postgresql://itam_user:itam_user@localhost:5432/postgres", connect_args={'options': '-csearch_path=itam'}) 23 | #self.engine = create_engine(f"postgresql://{os.environ['DB_USERNAME']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ['DB_PORT']}/{os.environ['DB_NAME']}", connect_args={'options': '-csearch_path={}'.format(os.environ['DB_SCHEMA'])}) 24 | self.Session = sessionmaker(bind=self.engine) 25 | 26 | def get_session(self): 27 | return self.Session() -------------------------------------------------------------------------------- /chapter_4/diagram2.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | User[User] --> ITAM_UI[ITAM User Interface] 3 | ITAM_UI --> AssetController[Asset Controller] 4 | ITAM_UI --> UserController[User Controller] 5 | 6 | AssetController --> AssetService[Asset Service] 7 | UserController --> UserService[User Service] 8 | 9 | AssetService --> HardwareRepository[Hardware Repository] 10 | AssetService --> VendorRepository[Vendor Repository] 11 | AssetService --> ProcurementRepository[Procurement Repository] 12 | UserService --> UserRepository[User Repository] 13 | 14 | HardwareRepository --> HardwareAPI[Hardware API] 15 | VendorRepository --> VendorAPI[Vendor API] 16 | ProcurementRepository --> ProcurementAPI[Procurement API] 17 | UserRepository --> AuthAPI[Authentication & Authorization API] 18 | 19 | HardwareAPI --> DB1[(Hardware Database)] 20 | VendorAPI --> DB2[(Vendor Database)] 21 | ProcurementAPI --> DB3[(Procurement Database)] 22 | AuthAPI --> DB4[(User Database)] 23 | 24 | class User user; 25 | class ITAM_UI ui; 26 | class AssetController assetController; 27 | class UserController userController; 28 | class AssetService assetService; 29 | class UserService userService; 30 | class HardwareRepository hardwareRepository; 31 | class VendorRepository vendorRepository; 32 | class ProcurementRepository procurementRepository; 33 | class UserRepository userRepository; 34 | class HardwareAPI hardwareAPI; 35 | class VendorAPI vendorAPI; 36 | class ProcurementAPI procurementAPI; 37 | class DB1 db1; 38 | class DB2 db2; 39 | class DB3 db3; 40 | class DB4 db4; -------------------------------------------------------------------------------- /chapter_5/diagram2.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | User[User] --> ITAM_UI[ITAM User Interface] 3 | ITAM_UI --> AssetController[Asset Controller] 4 | ITAM_UI --> UserController[User Controller] 5 | 6 | AssetController --> AssetService[Asset Service] 7 | UserController --> UserService[User Service] 8 | 9 | AssetService --> HardwareRepository[Hardware Repository] 10 | AssetService --> VendorRepository[Vendor Repository] 11 | AssetService --> ProcurementRepository[Procurement Repository] 12 | UserService --> UserRepository[User Repository] 13 | 14 | HardwareRepository --> HardwareAPI[Hardware API] 15 | VendorRepository --> VendorAPI[Vendor API] 16 | ProcurementRepository --> ProcurementAPI[Procurement API] 17 | UserRepository --> AuthAPI[Authentication & Authorization API] 18 | 19 | HardwareAPI --> DB1[(Hardware Database)] 20 | VendorAPI --> DB2[(Vendor Database)] 21 | ProcurementAPI --> DB3[(Procurement Database)] 22 | AuthAPI --> DB4[(User Database)] 23 | 24 | class User user; 25 | class ITAM_UI ui; 26 | class AssetController assetController; 27 | class UserController userController; 28 | class AssetService assetService; 29 | class UserService userService; 30 | class HardwareRepository hardwareRepository; 31 | class VendorRepository vendorRepository; 32 | class ProcurementRepository procurementRepository; 33 | class UserRepository userRepository; 34 | class HardwareAPI hardwareAPI; 35 | class VendorAPI vendorAPI; 36 | class ProcurementAPI procurementAPI; 37 | class DB1 db1; 38 | class DB2 db2; 39 | class DB3 db3; 40 | class DB4 db4; -------------------------------------------------------------------------------- /chapter_6/diagram2.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | User[User] --> ITAM_UI[ITAM User Interface] 3 | ITAM_UI --> AssetController[Asset Controller] 4 | ITAM_UI --> UserController[User Controller] 5 | 6 | AssetController --> AssetService[Asset Service] 7 | UserController --> UserService[User Service] 8 | 9 | AssetService --> HardwareRepository[Hardware Repository] 10 | AssetService --> VendorRepository[Vendor Repository] 11 | AssetService --> ProcurementRepository[Procurement Repository] 12 | UserService --> UserRepository[User Repository] 13 | 14 | HardwareRepository --> HardwareAPI[Hardware API] 15 | VendorRepository --> VendorAPI[Vendor API] 16 | ProcurementRepository --> ProcurementAPI[Procurement API] 17 | UserRepository --> AuthAPI[Authentication & Authorization API] 18 | 19 | HardwareAPI --> DB1[(Hardware Database)] 20 | VendorAPI --> DB2[(Vendor Database)] 21 | ProcurementAPI --> DB3[(Procurement Database)] 22 | AuthAPI --> DB4[(User Database)] 23 | 24 | class User user; 25 | class ITAM_UI ui; 26 | class AssetController assetController; 27 | class UserController userController; 28 | class AssetService assetService; 29 | class UserService userService; 30 | class HardwareRepository hardwareRepository; 31 | class VendorRepository vendorRepository; 32 | class ProcurementRepository procurementRepository; 33 | class UserRepository userRepository; 34 | class HardwareAPI hardwareAPI; 35 | class VendorAPI vendorAPI; 36 | class ProcurementAPI procurementAPI; 37 | class DB1 db1; 38 | class DB2 db2; 39 | class DB3 db3; 40 | class DB4 db4; -------------------------------------------------------------------------------- /chapter_7/diagram2.mmd: -------------------------------------------------------------------------------- 1 | graph LR 2 | User[User] --> ITAM_UI[ITAM User Interface] 3 | ITAM_UI --> AssetController[Asset Controller] 4 | ITAM_UI --> UserController[User Controller] 5 | 6 | AssetController --> AssetService[Asset Service] 7 | UserController --> UserService[User Service] 8 | 9 | AssetService --> HardwareRepository[Hardware Repository] 10 | AssetService --> VendorRepository[Vendor Repository] 11 | AssetService --> ProcurementRepository[Procurement Repository] 12 | UserService --> UserRepository[User Repository] 13 | 14 | HardwareRepository --> HardwareAPI[Hardware API] 15 | VendorRepository --> VendorAPI[Vendor API] 16 | ProcurementRepository --> ProcurementAPI[Procurement API] 17 | UserRepository --> AuthAPI[Authentication & Authorization API] 18 | 19 | HardwareAPI --> DB1[(Hardware Database)] 20 | VendorAPI --> DB2[(Vendor Database)] 21 | ProcurementAPI --> DB3[(Procurement Database)] 22 | AuthAPI --> DB4[(User Database)] 23 | 24 | class User user; 25 | class ITAM_UI ui; 26 | class AssetController assetController; 27 | class UserController userController; 28 | class AssetService assetService; 29 | class UserService userService; 30 | class HardwareRepository hardwareRepository; 31 | class VendorRepository vendorRepository; 32 | class ProcurementRepository procurementRepository; 33 | class UserRepository userRepository; 34 | class HardwareAPI hardwareAPI; 35 | class VendorAPI vendorAPI; 36 | class ProcurementAPI procurementAPI; 37 | class DB1 db1; 38 | class DB2 db2; 39 | class DB3 db3; 40 | class DB4 db4; -------------------------------------------------------------------------------- /chapter_4/itam/domain/line_of_business_statistics.py: -------------------------------------------------------------------------------- 1 | # Define a class called LineOfBusinessStatistics 2 | # with the following attributes 3 | # -line_of_business: LineOfBusiness 4 | # -total_cost: float 5 | # -total_depreciation: float 6 | # and with the following methods: 7 | # +__init__(self, line_of_business: LineOfBusiness, total_cost: float, total_depreciation: float) 8 | # +get_line_of_business(self) -> Department 9 | # +get_total_cost(self) -> float 10 | # +get_total_depreciation(self) -> float 11 | # +set_line_of_business(self, line_of_business: LineOfBusiness) 12 | # +set_total_cost(self, total_cost: float) 13 | # +set_total_depreciation(self, total_depreciation: float) 14 | 15 | class LineOfBusinessStatistics: 16 | def __init__(self, line_of_business, total_cost, total_depreciation): 17 | self.line_of_business = line_of_business 18 | self.total_cost = total_cost 19 | self.total_depreciation = total_depreciation 20 | 21 | def get_line_of_business(self): 22 | return self.line_of_business 23 | 24 | def get_total_cost(self): 25 | return self.total_cost 26 | 27 | def get_total_depreciation(self): 28 | return self.total_depreciation 29 | 30 | def set_line_of_business(self, line_of_business): 31 | self.line_of_business = line_of_business 32 | 33 | def set_total_cost(self, total_cost): 34 | self.total_cost = total_cost 35 | 36 | def set_total_depreciation(self, total_depreciation): 37 | self.total_depreciation = total_depreciation -------------------------------------------------------------------------------- /chapter_5/itam/domain/line_of_business_statistics.py: -------------------------------------------------------------------------------- 1 | # Define a class called LineOfBusinessStatistics 2 | # with the following attributes 3 | # -line_of_business: LineOfBusiness 4 | # -total_cost: float 5 | # -total_depreciation: float 6 | # and with the following methods: 7 | # +__init__(self, line_of_business: LineOfBusiness, total_cost: float, total_depreciation: float) 8 | # +get_line_of_business(self) -> Department 9 | # +get_total_cost(self) -> float 10 | # +get_total_depreciation(self) -> float 11 | # +set_line_of_business(self, line_of_business: LineOfBusiness) 12 | # +set_total_cost(self, total_cost: float) 13 | # +set_total_depreciation(self, total_depreciation: float) 14 | 15 | class LineOfBusinessStatistics: 16 | def __init__(self, line_of_business, total_cost, total_depreciation): 17 | self.line_of_business = line_of_business 18 | self.total_cost = total_cost 19 | self.total_depreciation = total_depreciation 20 | 21 | def get_line_of_business(self): 22 | return self.line_of_business 23 | 24 | def get_total_cost(self): 25 | return self.total_cost 26 | 27 | def get_total_depreciation(self): 28 | return self.total_depreciation 29 | 30 | def set_line_of_business(self, line_of_business): 31 | self.line_of_business = line_of_business 32 | 33 | def set_total_cost(self, total_cost): 34 | self.total_cost = total_cost 35 | 36 | def set_total_depreciation(self, total_depreciation): 37 | self.total_depreciation = total_depreciation -------------------------------------------------------------------------------- /chapter_6/itam/domain/line_of_business_statistics.py: -------------------------------------------------------------------------------- 1 | # Define a class called LineOfBusinessStatistics 2 | # with the following attributes 3 | # -line_of_business: LineOfBusiness 4 | # -total_cost: float 5 | # -total_depreciation: float 6 | # and with the following methods: 7 | # +__init__(self, line_of_business: LineOfBusiness, total_cost: float, total_depreciation: float) 8 | # +get_line_of_business(self) -> Department 9 | # +get_total_cost(self) -> float 10 | # +get_total_depreciation(self) -> float 11 | # +set_line_of_business(self, line_of_business: LineOfBusiness) 12 | # +set_total_cost(self, total_cost: float) 13 | # +set_total_depreciation(self, total_depreciation: float) 14 | 15 | class LineOfBusinessStatistics: 16 | def __init__(self, line_of_business, total_cost, total_depreciation): 17 | self.line_of_business = line_of_business 18 | self.total_cost = total_cost 19 | self.total_depreciation = total_depreciation 20 | 21 | def get_line_of_business(self): 22 | return self.line_of_business 23 | 24 | def get_total_cost(self): 25 | return self.total_cost 26 | 27 | def get_total_depreciation(self): 28 | return self.total_depreciation 29 | 30 | def set_line_of_business(self, line_of_business): 31 | self.line_of_business = line_of_business 32 | 33 | def set_total_cost(self, total_cost): 34 | self.total_cost = total_cost 35 | 36 | def set_total_depreciation(self, total_depreciation): 37 | self.total_depreciation = total_depreciation -------------------------------------------------------------------------------- /chapter_7/itam/domain/line_of_business_statistics.py: -------------------------------------------------------------------------------- 1 | # Define a class called LineOfBusinessStatistics 2 | # with the following attributes 3 | # -line_of_business: LineOfBusiness 4 | # -total_cost: float 5 | # -total_depreciation: float 6 | # and with the following methods: 7 | # +__init__(self, line_of_business: LineOfBusiness, total_cost: float, total_depreciation: float) 8 | # +get_line_of_business(self) -> Department 9 | # +get_total_cost(self) -> float 10 | # +get_total_depreciation(self) -> float 11 | # +set_line_of_business(self, line_of_business: LineOfBusiness) 12 | # +set_total_cost(self, total_cost: float) 13 | # +set_total_depreciation(self, total_depreciation: float) 14 | 15 | class LineOfBusinessStatistics: 16 | def __init__(self, line_of_business, total_cost, total_depreciation): 17 | self.line_of_business = line_of_business 18 | self.total_cost = total_cost 19 | self.total_depreciation = total_depreciation 20 | 21 | def get_line_of_business(self): 22 | return self.line_of_business 23 | 24 | def get_total_cost(self): 25 | return self.total_cost 26 | 27 | def get_total_depreciation(self): 28 | return self.total_depreciation 29 | 30 | def set_line_of_business(self, line_of_business): 31 | self.line_of_business = line_of_business 32 | 33 | def set_total_cost(self, total_cost): 34 | self.total_cost = total_cost 35 | 36 | def set_total_depreciation(self, total_depreciation): 37 | self.total_depreciation = total_depreciation -------------------------------------------------------------------------------- /chapter_6/itam/visitor/test_department_visitor.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from itam.visitor import DepartmentStatisticsVisitor 3 | from itam.domain.asset import Asset 4 | from itam.domain.department import Department 5 | from itam.domain.funding_details import FundingDetails 6 | from itam.domain.depreciation_strategy import StraightLineDepreciationStrategy, DoubleDecliningDepreciationStrategy 7 | from datetime import date 8 | from typing import List, Dict 9 | 10 | class TestDepartmentStatisticsVisitor(unittest.TestCase): 11 | def test_visit(self): 12 | visitor = DepartmentStatisticsVisitor() 13 | dept_it = Department(1, 'IT') 14 | dept_hr = Department(2, 'HR') 15 | 16 | 17 | funding_details1 = FundingDetails(0.33, { dept_it: 0.5, dept_hr: 0.5 }, StraightLineDepreciationStrategy(), None) 18 | funding_details2 = FundingDetails(0.25, { dept_it: 0.3, dept_hr: 0.7 }, DoubleDecliningDepreciationStrategy(), None) 19 | 20 | asset1 = Asset(id=1, name='Computer', status='In use', category='Hardware', cost=1000.0, useful_life=3, salvage_value=100.0, purchase_date=date.today(), locations=[], funding_details=funding_details1) 21 | asset2 = Asset(id=2, name='Printer', status='In use', category='Hardware', cost=500.0, useful_life=2,salvage_value=50.0, purchase_date=date.today(), locations=[], funding_details=funding_details2) 22 | 23 | 24 | #asset1.set_funding_details(funding_details1) 25 | #asset2.set_funding_details(funding_details2) 26 | 27 | visitor.visit(asset1) 28 | visitor.visit(asset2) 29 | self.assertEqual(visitor.get_total_cost(), 1500.0) 30 | self.assertEqual(visitor.get_total_depreciation(), 1300.0) 31 | #self.assertEqual(visitor.get_total_allocation(), 0.8) -------------------------------------------------------------------------------- /chapter_7/itam/visitor/test_department_visitor.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from itam.visitor import DepartmentStatisticsVisitor 3 | from itam.domain.asset import Asset 4 | from itam.domain.department import Department 5 | from itam.domain.funding_details import FundingDetails 6 | from itam.domain.depreciation_strategy import StraightLineDepreciationStrategy, DoubleDecliningDepreciationStrategy 7 | from datetime import date 8 | from typing import List, Dict 9 | 10 | class TestDepartmentStatisticsVisitor(unittest.TestCase): 11 | def test_visit(self): 12 | visitor = DepartmentStatisticsVisitor() 13 | dept_it = Department(1, 'IT') 14 | dept_hr = Department(2, 'HR') 15 | 16 | 17 | funding_details1 = FundingDetails(0.33, { dept_it: 0.5, dept_hr: 0.5 }, StraightLineDepreciationStrategy(), None) 18 | funding_details2 = FundingDetails(0.25, { dept_it: 0.3, dept_hr: 0.7 }, DoubleDecliningDepreciationStrategy(), None) 19 | 20 | asset1 = Asset(id=1, name='Computer', status='In use', category='Hardware', cost=1000.0, useful_life=3, salvage_value=100.0, purchase_date=date.today(), locations=[], funding_details=funding_details1) 21 | asset2 = Asset(id=2, name='Printer', status='In use', category='Hardware', cost=500.0, useful_life=2,salvage_value=50.0, purchase_date=date.today(), locations=[], funding_details=funding_details2) 22 | 23 | 24 | #asset1.set_funding_details(funding_details1) 25 | #asset2.set_funding_details(funding_details2) 26 | 27 | visitor.visit(asset1) 28 | visitor.visit(asset2) 29 | self.assertEqual(visitor.get_total_cost(), 1500.0) 30 | self.assertEqual(visitor.get_total_depreciation(), 1300.0) 31 | #self.assertEqual(visitor.get_total_allocation(), 0.8) -------------------------------------------------------------------------------- /chapter_4/itam/domain/factory/asset_factory.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetFactory 2 | # It should have the following methods: 3 | # +new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset 4 | # Create a function that will take a string and return a datetime 5 | # Use the AssetBuilder to create the Asset and use the FundingDetailsBuilder to create the FundingDetails 6 | 7 | from datetime import datetime 8 | from itam.domain.asset import Asset 9 | from itam.domain.hardware import Hardware 10 | from itam.domain.software import Software 11 | from itam.domain.funding_details import FundingDetails 12 | from itam.domain.builder.asset_builder import AssetBuilder, FundingDetailsBuilder 13 | 14 | class AssetFactory: 15 | def __init__(self): 16 | self.id = 0 17 | 18 | def date_from_string(self, date_string: str) -> datetime: 19 | return datetime.strptime(date_string, "%Y-%m-%d") 20 | 21 | def new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset: 22 | self.id += 1 23 | purchase_date = self.date_from_string(asset_purchase_date) 24 | a = AssetBuilder().with_id(self.id).with_name(asset_name).with_category(asset_type).with_cost(asset_cost).with_useful_life(useful_life).with_status("active").with_salvage_value(salvage_value).with_purchase_date(purchase_date).build() 25 | f = FundingDetailsBuilder().with_asset(a).with_depreciation_strategy(depreciation_strategy).with_depreciation_rate(depreciation_rate).build() 26 | 27 | a.funding_details = f 28 | return a -------------------------------------------------------------------------------- /chapter_5/itam/domain/factory/asset_factory.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetFactory 2 | # It should have the following methods: 3 | # +new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset 4 | # Create a function that will take a string and return a datetime 5 | # Use the AssetBuilder to create the Asset and use the FundingDetailsBuilder to create the FundingDetails 6 | 7 | from datetime import datetime 8 | from itam.domain.asset import Asset 9 | from itam.domain.hardware import Hardware 10 | from itam.domain.software import Software 11 | from itam.domain.funding_details import FundingDetails 12 | from itam.domain.builder.asset_builder import AssetBuilder, FundingDetailsBuilder 13 | 14 | class AssetFactory: 15 | def __init__(self): 16 | self.id = 0 17 | 18 | def date_from_string(self, date_string: str) -> datetime: 19 | return datetime.strptime(date_string, "%Y-%m-%d") 20 | 21 | def new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset: 22 | self.id += 1 23 | purchase_date = self.date_from_string(asset_purchase_date) 24 | a = AssetBuilder().with_id(self.id).with_name(asset_name).with_category(asset_type).with_cost(asset_cost).with_useful_life(useful_life).with_status("active").with_salvage_value(salvage_value).with_purchase_date(purchase_date).build() 25 | f = FundingDetailsBuilder().with_asset(a).with_depreciation_strategy(depreciation_strategy).with_depreciation_rate(depreciation_rate).build() 26 | 27 | a.funding_details = f 28 | return a -------------------------------------------------------------------------------- /chapter_6/itam/domain/factory/asset_factory.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetFactory 2 | # It should have the following methods: 3 | # +new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset 4 | # Create a function that will take a string and return a datetime 5 | # Use the AssetBuilder to create the Asset and use the FundingDetailsBuilder to create the FundingDetails 6 | 7 | from datetime import datetime 8 | from itam.domain.asset import Asset 9 | from itam.domain.hardware import Hardware 10 | from itam.domain.software import Software 11 | from itam.domain.funding_details import FundingDetails 12 | from itam.domain.builder.asset_builder import AssetBuilder, FundingDetailsBuilder 13 | 14 | class AssetFactory: 15 | def __init__(self): 16 | self.id = 0 17 | 18 | def date_from_string(self, date_string: str) -> datetime: 19 | return datetime.strptime(date_string, "%Y-%m-%d") 20 | 21 | def new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset: 22 | self.id += 1 23 | purchase_date = self.date_from_string(asset_purchase_date) 24 | a = AssetBuilder().with_id(self.id).with_name(asset_name).with_category(asset_type).with_cost(asset_cost).with_useful_life(useful_life).with_status("active").with_salvage_value(salvage_value).with_purchase_date(purchase_date).build() 25 | f = FundingDetailsBuilder().with_asset(a).with_depreciation_strategy(depreciation_strategy).with_depreciation_rate(depreciation_rate).build() 26 | 27 | a.funding_details = f 28 | return a -------------------------------------------------------------------------------- /chapter_7/itam/domain/factory/asset_factory.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetFactory 2 | # It should have the following methods: 3 | # +new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset 4 | # Create a function that will take a string and return a datetime 5 | # Use the AssetBuilder to create the Asset and use the FundingDetailsBuilder to create the FundingDetails 6 | 7 | from datetime import datetime 8 | from itam.domain.asset import Asset 9 | from itam.domain.hardware import Hardware 10 | from itam.domain.software import Software 11 | from itam.domain.funding_details import FundingDetails 12 | from itam.domain.builder.asset_builder import AssetBuilder, FundingDetailsBuilder 13 | 14 | class AssetFactory: 15 | def __init__(self): 16 | self.id = 0 17 | 18 | def date_from_string(self, date_string: str) -> datetime: 19 | return datetime.strptime(date_string, "%Y-%m-%d") 20 | 21 | def new(self, asset_type: str, asset_name: str, asset_cost: float, useful_life: int, depreciation_strategy: str, depreciation_rate: float, salvage_value: float, asset_purchase_date: str) -> Asset: 22 | self.id += 1 23 | purchase_date = self.date_from_string(asset_purchase_date) 24 | a = AssetBuilder().with_id(self.id).with_name(asset_name).with_category(asset_type).with_cost(asset_cost).with_useful_life(useful_life).with_status("active").with_salvage_value(salvage_value).with_purchase_date(purchase_date).build() 25 | f = FundingDetailsBuilder().with_asset(a).with_depreciation_strategy(depreciation_strategy).with_depreciation_rate(depreciation_rate).build() 26 | 27 | a.funding_details = f 28 | return a -------------------------------------------------------------------------------- /chapter_9/main.py: -------------------------------------------------------------------------------- 1 | import math 2 | import statistics 3 | 4 | def std_dev_chat_gpt_attempt_1(lst): 5 | # Step 1: Calculate the mean 6 | mean = sum(lst) / len(lst) 7 | 8 | # Step 2: Find squared differences 9 | squared_diffs = [(x - mean) ** 2 for x in lst] 10 | 11 | # Step 3: Compute the mean of squared differences 12 | mean_squared_diffs = sum(squared_diffs) / len(lst) 13 | 14 | # Step 4: Square root of the mean squared differences 15 | std_dev = mean_squared_diffs ** 0.5 16 | 17 | return std_dev 18 | 19 | 20 | def std_dev_llama_attempt_1(numbers): 21 | n = len(numbers) 22 | sum = 0 23 | for i in range(n): 24 | sum += numbers[i] ** 2 25 | return math.sqrt(sum / (n - 1)) 26 | 27 | 28 | def std_dev_llama_attempt_2(numbers): 29 | sum_squared = 0 30 | mean = statistics.mean(numbers) 31 | for num in numbers: 32 | sum_squared += (num - mean) ** 2 33 | 34 | # Compute the square root of the sum of the squares to get the standard deviation 35 | std_dev = math.sqrt(sum_squared/len(numbers)) 36 | return std_dev 37 | 38 | 39 | def std_dev_mistrail_attempt_1(numbers): 40 | mean = sum(numbers) / len(numbers) 41 | 42 | differences = [x - mean for x in numbers] # Subtract the mean from each number. 43 | squared_differences = [y * y for y in differences] # Square each difference. 44 | 45 | variance = sum(squared_differences) / len(numbers) # Calculate average of squared differences (variance). 46 | return math.sqrt(variance) # Return the standard deviation. 47 | 48 | 49 | 50 | if __name__ == '__main__': 51 | numbers = [1, 2, 3, 4, 5] 52 | print(std_dev_chat_gpt_attempt_1(numbers)) 53 | print(std_dev_llama_attempt_1(numbers)) 54 | print(std_dev_llama_attempt_2(numbers)) 55 | print(std_dev_mistrail_attempt_1(numbers)) 56 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/asset_manager.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | from asset import Asset 3 | 4 | class AssetManager: 5 | def __init__(self): 6 | self.assets: List[Asset] = [] 7 | 8 | def add_asset(self, asset: Asset): 9 | self.assets.append(asset) 10 | 11 | def remove_asset(self, asset_id: str) -> bool: 12 | for asset in self.assets: 13 | if asset.asset_id == asset_id: 14 | self.assets.remove(asset) 15 | return True 16 | return False 17 | 18 | def get_asset_by_id(self, asset_id: str) -> Optional[Asset]: 19 | for asset in self.assets: 20 | if asset.asset_id == asset_id: 21 | return asset 22 | return None 23 | 24 | def assign_asset(self, asset_id: str, user: str) -> bool: 25 | for asset in self.assets: 26 | if asset.asset_id == asset_id: 27 | if asset.status == 'Available': 28 | asset.assign_to_user(user) 29 | return True 30 | else: 31 | return False 32 | return False 33 | 34 | def unassign_asset(self, asset_id: str) -> bool: 35 | for asset in self.assets: 36 | if asset.asset_id == asset_id: 37 | if asset.status == 'Assigned': 38 | asset.unassign() 39 | return True 40 | else: 41 | return False 42 | return False 43 | 44 | def get_available_assets(self) -> List[Asset]: 45 | return [asset for asset in self.assets if asset.status == 'Available'] 46 | 47 | def get_assigned_assets(self) -> List[Asset]: 48 | return [asset for asset in self.assets if asset.status == 'Assigned'] 49 | 50 | def get_all_assets(self) -> List[Asset]: 51 | return self.assets 52 | -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/asset_manager.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | from asset import Asset 3 | 4 | class AssetManager: 5 | def __init__(self): 6 | self.assets: List[Asset] = [] 7 | 8 | def add_asset(self, asset: Asset): 9 | self.assets.append(asset) 10 | 11 | def remove_asset(self, asset_id: str) -> bool: 12 | for asset in self.assets: 13 | if asset.asset_id == asset_id: 14 | self.assets.remove(asset) 15 | return True 16 | return False 17 | 18 | def get_asset_by_id(self, asset_id: str) -> Optional[Asset]: 19 | for asset in self.assets: 20 | if asset.asset_id == asset_id: 21 | return asset 22 | return None 23 | 24 | def assign_asset(self, asset_id: str, user: str) -> bool: 25 | for asset in self.assets: 26 | if asset.asset_id == asset_id: 27 | if asset.status == 'Available': 28 | asset.assign_to_user(user) 29 | return True 30 | else: 31 | return False 32 | return False 33 | 34 | def unassign_asset(self, asset_id: str) -> bool: 35 | for asset in self.assets: 36 | if asset.asset_id == asset_id: 37 | if asset.status == 'Assigned': 38 | asset.unassign() 39 | return True 40 | else: 41 | return False 42 | return False 43 | 44 | def get_available_assets(self) -> List[Asset]: 45 | return [asset for asset in self.assets if asset.status == 'Available'] 46 | 47 | def get_assigned_assets(self) -> List[Asset]: 48 | return [asset for asset in self.assets if asset.status == 'Assigned'] 49 | 50 | def get_all_assets(self) -> List[Asset]: 51 | return self.assets 52 | -------------------------------------------------------------------------------- /chapter_6/features/steps/steps.py: -------------------------------------------------------------------------------- 1 | from behave import given, when, then 2 | from itam.service.asset_manager import AssetManager 3 | from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository 4 | from itam.domain.asset import Asset 5 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 6 | from unittest.mock import Mock 7 | 8 | @given('the Asset Manager is running') 9 | def step_impl(context): 10 | context.asset_repository = InMemoryAssetRepository() 11 | context.asset_location_mediator = Mock(spec=AssetLocationMediator) 12 | context.asset_manager = AssetManager(context.asset_repository, context.asset_location_mediator) 13 | 14 | @given('the InMemoryAssetRepository is initialized') 15 | def step_impl(context): 16 | pass 17 | 18 | @given('the AssetLocationMediator is mocked') 19 | def step_impl(context): 20 | pass 21 | 22 | @when('I create an asset with a cost of ${cost}') 23 | def step_impl(context, cost): 24 | asset = Asset(id=1, name='Test Asset 1', status='Available', category='Test Category', cost=float(cost), useful_life=5, salvage_value=0, purchase_date='2022-01-01', locations=['Test Location'], funding_details={'Test Funding': 1000}) 25 | context.asset_manager.create(asset) 26 | 27 | @when('I create another asset with a cost of ${cost}') 28 | def step_impl(context, cost): 29 | asset = Asset(id=2, name='Test Asset 2', status='Available', category='Test Category', cost=float(cost), useful_life=5, salvage_value=0, purchase_date='2022-01-01', locations=['Test Location'], funding_details={'Test Funding': 1000}) 30 | context.asset_manager.create(asset) 31 | 32 | @then('the total cost of all assets should be ${total_cost}') 33 | def step_impl(context, total_cost): 34 | assets = context.asset_manager.get_assets() 35 | assert sum(asset.cost for asset in assets) == float(total_cost) -------------------------------------------------------------------------------- /chapter_7/features/steps/steps.py: -------------------------------------------------------------------------------- 1 | from behave import given, when, then 2 | from itam.service.asset_manager import AssetManager 3 | from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository 4 | from itam.domain.asset import Asset 5 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 6 | from unittest.mock import Mock 7 | 8 | @given('the Asset Manager is running') 9 | def step_impl(context): 10 | context.asset_repository = InMemoryAssetRepository() 11 | context.asset_location_mediator = Mock(spec=AssetLocationMediator) 12 | context.asset_manager = AssetManager(context.asset_repository, context.asset_location_mediator) 13 | 14 | @given('the InMemoryAssetRepository is initialized') 15 | def step_impl(context): 16 | pass 17 | 18 | @given('the AssetLocationMediator is mocked') 19 | def step_impl(context): 20 | pass 21 | 22 | @when('I create an asset with a cost of ${cost}') 23 | def step_impl(context, cost): 24 | asset = Asset(id=1, name='Test Asset 1', status='Available', category='Test Category', cost=float(cost), useful_life=5, salvage_value=0, purchase_date='2022-01-01', locations=['Test Location'], funding_details={'Test Funding': 1000}) 25 | context.asset_manager.create(asset) 26 | 27 | @when('I create another asset with a cost of ${cost}') 28 | def step_impl(context, cost): 29 | asset = Asset(id=2, name='Test Asset 2', status='Available', category='Test Category', cost=float(cost), useful_life=5, salvage_value=0, purchase_date='2022-01-01', locations=['Test Location'], funding_details={'Test Funding': 1000}) 30 | context.asset_manager.create(asset) 31 | 32 | @then('the total cost of all assets should be ${total_cost}') 33 | def step_impl(context, total_cost): 34 | assets = context.asset_manager.get_assets() 35 | assert sum(asset.cost for asset in assets) == float(total_cost) -------------------------------------------------------------------------------- /chapter_2/chatgpt-flask/asset.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | class Asset(): 4 | def __init__(self, asset_id: str, asset_type: str, manufacturer: str, model: str, purchase_date: str, warranty_end_date: str, location: str): 5 | self.asset_id = asset_id 6 | self.asset_type = asset_type 7 | self.manufacturer = manufacturer 8 | self.model = model 9 | self.purchase_date = purchase_date 10 | self.warranty_end_date = warranty_end_date 11 | self.location = location 12 | self.assigned_to: Optional[str] = None 13 | self.status: str = 'Available' 14 | 15 | def assign_to_user(self, user: str): 16 | self.assigned_to = user 17 | self.status = 'Assigned' 18 | 19 | def unassign(self): 20 | self.assigned_to = None 21 | self.status = 'Available' 22 | 23 | def get_details(self): 24 | details = f"Asset ID: {self.asset_id}\n" 25 | details += f"Type: {self.asset_type}\n" 26 | details += f"Manufacturer: {self.manufacturer}\n" 27 | details += f"Model: {self.model}\n" 28 | details += f"Purchase Date: {self.purchase_date}\n" 29 | details += f"Warranty End Date: {self.warranty_end_date}\n" 30 | details += f"Location: {self.location}\n" 31 | details += f"Assigned To: {self.assigned_to}\n" 32 | details += f"Status: {self.status}\n" 33 | return details 34 | 35 | def to_dict(self): 36 | return { 37 | "asset_id": self.asset_id, 38 | "asset_type": self.asset_type, 39 | "manufacturer": self.manufacturer, 40 | "model": self.model, 41 | "purchase_date": self.purchase_date, 42 | "warranty_end_date": self.warranty_end_date, 43 | "location": self.location, 44 | "assigned_to": self.assigned_to, 45 | "status": self.status 46 | } -------------------------------------------------------------------------------- /chapter_2/chatgpt-fastapi/asset.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | class Asset(): 4 | def __init__(self, asset_id: str, asset_type: str, manufacturer: str, model: str, purchase_date: str, warranty_end_date: str, location: str): 5 | self.asset_id = asset_id 6 | self.asset_type = asset_type 7 | self.manufacturer = manufacturer 8 | self.model = model 9 | self.purchase_date = purchase_date 10 | self.warranty_end_date = warranty_end_date 11 | self.location = location 12 | self.assigned_to: Optional[str] = None 13 | self.status: str = 'Available' 14 | 15 | def assign_to_user(self, user: str): 16 | self.assigned_to = user 17 | self.status = 'Assigned' 18 | 19 | def unassign(self): 20 | self.assigned_to = None 21 | self.status = 'Available' 22 | 23 | def get_details(self): 24 | details = f"Asset ID: {self.asset_id}\n" 25 | details += f"Type: {self.asset_type}\n" 26 | details += f"Manufacturer: {self.manufacturer}\n" 27 | details += f"Model: {self.model}\n" 28 | details += f"Purchase Date: {self.purchase_date}\n" 29 | details += f"Warranty End Date: {self.warranty_end_date}\n" 30 | details += f"Location: {self.location}\n" 31 | details += f"Assigned To: {self.assigned_to}\n" 32 | details += f"Status: {self.status}\n" 33 | return details 34 | 35 | def to_dict(self): 36 | return { 37 | "asset_id": self.asset_id, 38 | "asset_type": self.asset_type, 39 | "manufacturer": self.manufacturer, 40 | "model": self.model, 41 | "purchase_date": self.purchase_date, 42 | "warranty_end_date": self.warranty_end_date, 43 | "location": self.location, 44 | "assigned_to": self.assigned_to, 45 | "status": self.status 46 | } -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/api/asset_model.py: -------------------------------------------------------------------------------- 1 | # Define a pydantic model for AssetIn 2 | # It should have the following attributes: 3 | # name: str 4 | # asset_type: str 5 | # department: str 6 | # depreciation_strategy: str 7 | # useful_life: int 8 | # unit_cost: float 9 | # depreciation_rate: float 10 | # salvage_value: float 11 | 12 | # Define a pydantic model for AssetOut 13 | # It should have the following attributes: 14 | # id: int 15 | # name: str 16 | # asset_type: str 17 | # department: str 18 | # depreciation_strategy: str 19 | # useful_life: int 20 | # unit_cost: float 21 | # depreciation_rate: float 22 | # salvage_value: float 23 | # It should have a method that transforms an Asset into an AssetOut 24 | 25 | from pydantic import BaseModel 26 | from itam.domain.asset import Asset 27 | 28 | class AssetIn(BaseModel): 29 | name: str 30 | asset_type: str 31 | department: str 32 | depreciation_strategy: str 33 | useful_life: int 34 | unit_cost: float 35 | depreciation_rate: float 36 | salvage_value: float 37 | purchase_date: str 38 | 39 | class AssetOut(BaseModel): 40 | id: int 41 | name: str 42 | asset_type: str 43 | depreciation_strategy: str 44 | useful_life: int 45 | unit_cost: float 46 | depreciation_rate: float 47 | salvage_value: float 48 | purchase_date: str 49 | 50 | @staticmethod 51 | def from_asset(asset: Asset) -> AssetOut: 52 | return AssetOut( 53 | id=asset.id, 54 | name=asset.name, 55 | asset_type=asset.category, 56 | depreciation_strategy=str(asset.funding_details.depreciation_strategy), 57 | useful_life=asset.useful_life, 58 | unit_cost=asset.cost, 59 | depreciation_rate=asset.funding_details.depreciation_rate, 60 | salvage_value=asset.salvage_value, 61 | purchase_date=asset.purchase_date.strftime("%Y-%m-%d"), 62 | ) -------------------------------------------------------------------------------- /chapter_5/main.py: -------------------------------------------------------------------------------- 1 | # Importing the necessary modules and packages 2 | # Instantiating the necessary objects and components, such as the FastAPI application and database connection 3 | # Configuring the application settings and environment variables 4 | # Mounting the HTTP controllers and endpoints to the FastAPI application 5 | # Starting the server and running the application 6 | from pyspark.sql import SparkSession 7 | from fastapi import FastAPI 8 | from itam.infrastructure.api.asset_controller import AssetController 9 | #from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository 10 | from itam.infrastructure.repository.sqlalchemy_asset_repository import SQLAlchemyAssetRepository 11 | from itam.infrastructure.database.database_connection import DatabaseConnection 12 | from itam.service.asset_manager import AssetManager 13 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 14 | from itam.infrastructure.adapters.asset_rest_adapter import AssetRestAdapter 15 | from itam.infrastructure.consumers.asset_location_kafka_consumer import AssetLocationKafkaConsumer 16 | from itam.infrastructure.adapters.asset_location_spark_adapter import AssetLocationSparkAdapter 17 | import uvicorn 18 | 19 | app = FastAPI() 20 | session = DatabaseConnection().get_session() 21 | #repository = InMemoryAssetRepository() 22 | repository = SQLAlchemyAssetRepository(session) 23 | mediator = AssetLocationMediator() 24 | asset_manager = AssetManager(repository, mediator) 25 | asset_rest_adapter = AssetRestAdapter(asset_manager) 26 | asset_controller = AssetController(asset_rest_adapter) 27 | 28 | app.include_router(asset_controller.get_router()) 29 | 30 | #consumer = AssetLocationKafkaConsumer(mediator) 31 | #consumer.start_consumer() 32 | 33 | spark_adapter = AssetLocationSparkAdapter() 34 | spark_adapter.run() 35 | app.include_router(asset_controller.get_router()) 36 | 37 | if __name__ == '__main__': 38 | uvicorn.run(app, host='0.0.0.0', port=8000) -------------------------------------------------------------------------------- /chapter_7/main.py: -------------------------------------------------------------------------------- 1 | # Importing the necessary modules and packages 2 | # Instantiating the necessary objects and components, such as the FastAPI application and database connection 3 | # Configuring the application settings and environment variables 4 | # Mounting the HTTP controllers and endpoints to the FastAPI application 5 | # Starting the server and running the application 6 | from pyspark.sql import SparkSession 7 | from fastapi import FastAPI 8 | from itam.infrastructure.api.asset_controller import AssetController 9 | #from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository 10 | from itam.infrastructure.repository.sqlalchemy_asset_repository import SQLAlchemyAssetRepository 11 | from itam.infrastructure.database.database_connection import DatabaseConnection 12 | from itam.service.asset_manager import AssetManager 13 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 14 | from itam.infrastructure.adapters.asset_rest_adapter import AssetRestAdapter 15 | from itam.infrastructure.consumers.asset_location_kafka_consumer import AssetLocationKafkaConsumer 16 | from itam.infrastructure.adapters.asset_location_spark_adapter import AssetLocationSparkAdapter 17 | import uvicorn 18 | 19 | app = FastAPI() 20 | session = DatabaseConnection().get_session() 21 | #repository = InMemoryAssetRepository() 22 | repository = SQLAlchemyAssetRepository(session) 23 | mediator = AssetLocationMediator() 24 | asset_manager = AssetManager(repository, mediator) 25 | asset_rest_adapter = AssetRestAdapter(asset_manager) 26 | asset_controller = AssetController(asset_rest_adapter) 27 | 28 | app.include_router(asset_controller.get_router()) 29 | 30 | #consumer = AssetLocationKafkaConsumer(mediator) 31 | #consumer.start_consumer() 32 | 33 | #spark_adapter = AssetLocationSparkAdapter() 34 | #spark_adapter.run() 35 | app.include_router(asset_controller.get_router()) 36 | 37 | if __name__ == '__main__': 38 | uvicorn.run(app, host='0.0.0.0', port=8000) -------------------------------------------------------------------------------- /chapter_6/main.py: -------------------------------------------------------------------------------- 1 | # Importing the necessary modules and packages 2 | # Instantiating the necessary objects and components, such as the FastAPI application and database connection 3 | # Configuring the application settings and environment variables 4 | # Mounting the HTTP controllers and endpoints to the FastAPI application 5 | # Starting the server and running the application 6 | #from pyspark.sql import SparkSession 7 | from fastapi import FastAPI 8 | from itam.infrastructure.api.asset_controller import AssetController 9 | #from itam.infrastructure.repository.in_memory_asset_repository import InMemoryAssetRepository 10 | from itam.infrastructure.repository.sqlalchemy_asset_repository import SQLAlchemyAssetRepository 11 | from itam.infrastructure.database.database_connection import DatabaseConnection 12 | from itam.service.asset_manager import AssetManager 13 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 14 | from itam.infrastructure.adapters.asset_rest_adapter import AssetRestAdapter 15 | from itam.infrastructure.consumers.asset_location_kafka_consumer import AssetLocationKafkaConsumer 16 | from itam.infrastructure.adapters.asset_location_spark_adapter import AssetLocationSparkAdapter 17 | import uvicorn 18 | 19 | #app = FastAPI() 20 | #session = DatabaseConnection().get_session() 21 | #repository = InMemoryAssetRepository() 22 | #repository = SQLAlchemyAssetRepository(session) 23 | #mediator = AssetLocationMediator() 24 | #asset_manager = AssetManager(repository, mediator) 25 | #asset_rest_adapter = AssetRestAdapter(asset_manager) 26 | #asset_controller = AssetController(asset_rest_adapter) 27 | 28 | #app.include_router(asset_controller.get_router()) 29 | 30 | #consumer = AssetLocationKafkaConsumer(mediator) 31 | #consumer.start_consumer() 32 | 33 | #spark_adapter = AssetLocationSparkAdapter() 34 | #spark_adapter.run() 35 | #app.include_router(asset_controller.get_router()) 36 | 37 | #if __name__ == '__main__': 38 | # uvicorn.run(app, host='0.0.0.0', port=8000) 39 | 40 | 41 | -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/api/asset_model.py: -------------------------------------------------------------------------------- 1 | # Define a pydantic model for AssetIn 2 | # It should have the following attributes: 3 | # name: str 4 | # asset_type: str 5 | # department: str 6 | # depreciation_strategy: str 7 | # useful_life: int 8 | # unit_cost: float 9 | # depreciation_rate: float 10 | # salvage_value: float 11 | 12 | # Define a pydantic model for AssetOut 13 | # It should have the following attributes: 14 | # id: int 15 | # name: str 16 | # asset_type: str 17 | # department: str 18 | # depreciation_strategy: str 19 | # useful_life: int 20 | # unit_cost: float 21 | # depreciation_rate: float 22 | # salvage_value: float 23 | # It should have a method that transforms an Asset into an AssetOut 24 | 25 | from pydantic import BaseModel 26 | from itam.domain.asset import Asset 27 | 28 | class AssetIn(BaseModel): 29 | name: str 30 | asset_type: str 31 | department: str 32 | depreciation_strategy: str 33 | useful_life: int 34 | unit_cost: float 35 | depreciation_rate: float 36 | salvage_value: float 37 | purchase_date: str 38 | 39 | class AssetOut(BaseModel): 40 | id: int 41 | name: str 42 | asset_type: str 43 | depreciation_strategy: str 44 | useful_life: int 45 | unit_cost: float 46 | depreciation_rate: float 47 | salvage_value: float 48 | purchase_date: str 49 | 50 | @staticmethod 51 | def from_asset(asset: Asset) -> AssetOut: 52 | return AssetOut( 53 | id=asset.id, 54 | name=asset.name, 55 | asset_type=asset.category, 56 | depreciation_strategy = str(asset.funding_details.depreciation_strategy) if asset.funding_details is not None else "", 57 | useful_life=asset.useful_life, 58 | unit_cost=asset.cost, 59 | depreciation_rate=asset.funding_details.depreciation_rate if asset.funding_details is not None else 0.0, 60 | salvage_value=asset.salvage_value, 61 | purchase_date=asset.purchase_date.strftime("%Y-%m-%d"), 62 | ) -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/api/asset_model.py: -------------------------------------------------------------------------------- 1 | # Define a pydantic model for AssetIn 2 | # It should have the following attributes: 3 | # name: str 4 | # asset_type: str 5 | # department: str 6 | # depreciation_strategy: str 7 | # useful_life: int 8 | # unit_cost: float 9 | # depreciation_rate: float 10 | # salvage_value: float 11 | 12 | # Define a pydantic model for AssetOut 13 | # It should have the following attributes: 14 | # id: int 15 | # name: str 16 | # asset_type: str 17 | # department: str 18 | # depreciation_strategy: str 19 | # useful_life: int 20 | # unit_cost: float 21 | # depreciation_rate: float 22 | # salvage_value: float 23 | # It should have a method that transforms an Asset into an AssetOut 24 | 25 | from pydantic import BaseModel 26 | from itam.domain.asset import Asset 27 | 28 | class AssetIn(BaseModel): 29 | name: str 30 | asset_type: str 31 | department: str 32 | depreciation_strategy: str 33 | useful_life: int 34 | unit_cost: float 35 | depreciation_rate: float 36 | salvage_value: float 37 | purchase_date: str 38 | 39 | class AssetOut(BaseModel): 40 | id: int 41 | name: str 42 | asset_type: str 43 | depreciation_strategy: str 44 | useful_life: int 45 | unit_cost: float 46 | depreciation_rate: float 47 | salvage_value: float 48 | purchase_date: str 49 | 50 | @staticmethod 51 | def from_asset(asset: Asset) -> AssetOut: 52 | return AssetOut( 53 | id=asset.id, 54 | name=asset.name, 55 | asset_type=asset.category, 56 | depreciation_strategy = str(asset.funding_details.depreciation_strategy) if asset.funding_details is not None else "", 57 | useful_life=asset.useful_life, 58 | unit_cost=asset.cost, 59 | depreciation_rate=asset.funding_details.depreciation_rate if asset.funding_details is not None else 0.0, 60 | salvage_value=asset.salvage_value, 61 | purchase_date=asset.purchase_date.strftime("%Y-%m-%d"), 62 | ) -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/api/asset_model.py: -------------------------------------------------------------------------------- 1 | # Define a pydantic model for AssetIn 2 | # It should have the following attributes: 3 | # name: str 4 | # asset_type: str 5 | # department: str 6 | # depreciation_strategy: str 7 | # useful_life: int 8 | # unit_cost: float 9 | # depreciation_rate: float 10 | # salvage_value: float 11 | 12 | # Define a pydantic model for AssetOut 13 | # It should have the following attributes: 14 | # id: int 15 | # name: str 16 | # asset_type: str 17 | # department: str 18 | # depreciation_strategy: str 19 | # useful_life: int 20 | # unit_cost: float 21 | # depreciation_rate: float 22 | # salvage_value: float 23 | # It should have a method that transforms an Asset into an AssetOut 24 | 25 | from pydantic import BaseModel 26 | from itam.domain.asset import Asset 27 | 28 | class AssetIn(BaseModel): 29 | name: str 30 | asset_type: str 31 | department: str 32 | depreciation_strategy: str 33 | useful_life: int 34 | unit_cost: float 35 | depreciation_rate: float 36 | salvage_value: float 37 | purchase_date: str 38 | 39 | class AssetOut(BaseModel): 40 | id: int 41 | name: str 42 | asset_type: str 43 | depreciation_strategy: str 44 | useful_life: int 45 | unit_cost: float 46 | depreciation_rate: float 47 | salvage_value: float 48 | purchase_date: str 49 | 50 | @staticmethod 51 | def from_asset(asset: Asset) -> AssetOut: 52 | return AssetOut( 53 | id=asset.id, 54 | name=asset.name, 55 | asset_type=asset.category, 56 | depreciation_strategy = str(asset.funding_details.depreciation_strategy) if asset.funding_details is not None else "", 57 | useful_life=asset.useful_life, 58 | unit_cost=asset.cost, 59 | depreciation_rate=asset.funding_details.depreciation_rate if asset.funding_details is not None else 0.0, 60 | salvage_value=asset.salvage_value, 61 | purchase_date=asset.purchase_date.strftime("%Y-%m-%d"), 62 | ) -------------------------------------------------------------------------------- /chapter_5/itam/service/asset_manager.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetManager 2 | # with CRUD operations for Asset 3 | # and a method to notify observers whenever an asset is created, updated or deleted 4 | # The AssetManager should accpet an instance of the BaseRepository[Asset] for data access and CRUD operations on Asset objects. 5 | # Implement methods for creating, reading, updating, and deleting assets using the AssetRepository instance. 6 | # Please include type hints for the input parameters and return values. 7 | # The methods should be named create, read, update, get_assets, and delete. 8 | 9 | from itam.domain.asset import Asset 10 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 11 | from itam.domain.events.asset_location_updated import AssetLocationUpdated 12 | from itam.infrastructure.repository.base_repository import BaseRepository 13 | 14 | class AssetManager: 15 | def __init__(self, base_repository: BaseRepository[Asset], mediator: AssetLocationMediator): 16 | self._repository = base_repository 17 | self.mediator = mediator 18 | self.mediator.register_handler(AssetLocationUpdated, self.update_asset_location) 19 | 20 | def create(self, asset: Asset) -> Asset: 21 | self._repository.create(asset) 22 | return asset 23 | 24 | def read(self, asset_id: int) -> Asset: 25 | return self._repository.read(asset_id) 26 | 27 | def update(self, asset: Asset) -> Asset: 28 | self._repository.update(asset) 29 | return asset 30 | 31 | def get_assets(self) -> list[Asset]: 32 | return self._repository.get_entities() 33 | 34 | def delete(self, asset_id: int) -> None: 35 | self._repository.delete(asset_id) 36 | 37 | def update_asset_location(self, event: AssetLocationUpdated) -> None: 38 | asset = self.read(event.asset_id) 39 | asset.add_location(event.latitude, event.longitude, event.timestamp) 40 | #self.update(asset) 41 | print(f"Asset {asset.id} location updated to {event.latitude}, {event.longitude} at {event.timestamp}") -------------------------------------------------------------------------------- /chapter_6/itam/service/asset_manager.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetManager 2 | # with CRUD operations for Asset 3 | # and a method to notify observers whenever an asset is created, updated or deleted 4 | # The AssetManager should accpet an instance of the BaseRepository[Asset] for data access and CRUD operations on Asset objects. 5 | # Implement methods for creating, reading, updating, and deleting assets using the AssetRepository instance. 6 | # Please include type hints for the input parameters and return values. 7 | # The methods should be named create, read, update, get_assets, and delete. 8 | 9 | from itam.domain.asset import Asset 10 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 11 | from itam.domain.events.asset_location_updated import AssetLocationUpdated 12 | from itam.infrastructure.repository.base_repository import BaseRepository 13 | 14 | class AssetManager: 15 | def __init__(self, base_repository: BaseRepository[Asset], mediator: AssetLocationMediator): 16 | self._repository = base_repository 17 | self.mediator = mediator 18 | self.mediator.register_handler(AssetLocationUpdated, self.update_asset_location) 19 | 20 | def create(self, asset: Asset) -> Asset: 21 | self._repository.create(asset) 22 | return asset 23 | 24 | def read(self, asset_id: int) -> Asset: 25 | return self._repository.read(asset_id) 26 | 27 | def update(self, asset: Asset) -> Asset: 28 | self._repository.update(asset) 29 | return asset 30 | 31 | def get_assets(self) -> list[Asset]: 32 | return self._repository.get_entities() 33 | 34 | def delete(self, asset_id: int) -> None: 35 | self._repository.delete(asset_id) 36 | 37 | def update_asset_location(self, event: AssetLocationUpdated) -> None: 38 | asset = self.read(event.asset_id) 39 | asset.add_location(event.latitude, event.longitude, event.timestamp) 40 | #self.update(asset) 41 | print(f"Asset {asset.id} location updated to {event.latitude}, {event.longitude} at {event.timestamp}") -------------------------------------------------------------------------------- /chapter_7/itam/service/asset_manager.py: -------------------------------------------------------------------------------- 1 | # Define a class called AssetManager 2 | # with CRUD operations for Asset 3 | # and a method to notify observers whenever an asset is created, updated or deleted 4 | # The AssetManager should accpet an instance of the BaseRepository[Asset] for data access and CRUD operations on Asset objects. 5 | # Implement methods for creating, reading, updating, and deleting assets using the AssetRepository instance. 6 | # Please include type hints for the input parameters and return values. 7 | # The methods should be named create, read, update, get_assets, and delete. 8 | 9 | from itam.domain.asset import Asset 10 | from itam.infrastructure.mediators.asset_location_mediator import AssetLocationMediator 11 | from itam.domain.events.asset_location_updated import AssetLocationUpdated 12 | from itam.infrastructure.repository.base_repository import BaseRepository 13 | 14 | class AssetManager: 15 | def __init__(self, base_repository: BaseRepository[Asset], mediator: AssetLocationMediator): 16 | self._repository = base_repository 17 | self.mediator = mediator 18 | self.mediator.register_handler(AssetLocationUpdated, self.update_asset_location) 19 | 20 | def create(self, asset: Asset) -> Asset: 21 | self._repository.create(asset) 22 | return asset 23 | 24 | def read(self, asset_id: int) -> Asset: 25 | return self._repository.read(asset_id) 26 | 27 | def update(self, asset: Asset) -> Asset: 28 | self._repository.update(asset) 29 | return asset 30 | 31 | def get_assets(self) -> list[Asset]: 32 | return self._repository.get_entities() 33 | 34 | def delete(self, asset_id: int) -> None: 35 | self._repository.delete(asset_id) 36 | 37 | def update_asset_location(self, event: AssetLocationUpdated) -> None: 38 | asset = self.read(event.asset_id) 39 | asset.add_location(event.latitude, event.longitude, event.timestamp) 40 | #self.update(asset) 41 | print(f"Asset {asset.id} location updated to {event.latitude}, {event.longitude} at {event.timestamp}") -------------------------------------------------------------------------------- /chapter_4/itam/domain/asset.py: -------------------------------------------------------------------------------- 1 | # Define a class named Asset 2 | # It should have the following attributes: 3 | # - id: int 4 | # - name: str 5 | # - status: str 6 | # - category: str 7 | # - cost: float 8 | # - useful_life: float 9 | # - salvage_value: float 10 | # - funding_details: FundingDetails 11 | # 12 | # The attributes cannot be None and cannot be added after construction 13 | # However, we should be able to access the attributes using methods 14 | 15 | from dataclasses import dataclass 16 | from datetime import date 17 | 18 | @dataclass 19 | class Asset(): 20 | id: int 21 | name: str 22 | status: str 23 | category: str 24 | cost: float 25 | useful_life: float 26 | salvage_value: float 27 | purchase_date: date 28 | 29 | def __post_init__(self): 30 | if self.id is None: 31 | raise TypeError("ID cannot be None") 32 | if self.name is None: 33 | raise TypeError("Name cannot be None") 34 | if self.status is None: 35 | raise TypeError("Status cannot be None") 36 | if self.category is None: 37 | raise TypeError("Category cannot be None") 38 | if self.cost is None: 39 | raise TypeError("Cost cannot be None") 40 | if self.useful_life is None: 41 | raise TypeError("Useful life cannot be None") 42 | if self.salvage_value is None: 43 | raise TypeError("Salvage value cannot be None") 44 | 45 | def get_id(self): 46 | return self.id 47 | 48 | def get_name(self): 49 | return self.name 50 | 51 | def get_status(self): 52 | return self.status 53 | 54 | def get_category(self): 55 | return self.category 56 | 57 | def get_cost(self): 58 | return self.cost 59 | 60 | def get_useful_life(self): 61 | return self.useful_life 62 | 63 | def get_salvage_value(self): 64 | return self.salvage_value 65 | 66 | def set_funding_details(self, funding_details): 67 | if (self.funding_details is None): 68 | self.funding_details = funding_details 69 | 70 | def get_funding_details(self): 71 | return self.funding_details -------------------------------------------------------------------------------- /chapter_4/itam/infrastructure/adapters/asset_database_adapter.py: -------------------------------------------------------------------------------- 1 | # Create a class called AssetDatabaseAdapter that implements the DatabasePort interface 2 | # This class will handle the database operations using a SQLAlchemy session. 3 | # The adapter should interact with Asset. 4 | # Implement methods for creating, getting, updating, and deleting assets, as well as listing all assets. 5 | # The adapter should not interact with the domain model directly. 6 | # The get_asset method should return a single Asset based off of the asset_id parameter. 7 | # The get_assets method should return a list of all assets from the database. 8 | # The create method should take an Asset object as a parameter and create a new row in the database as well as return the new Asset object. 9 | # The update method should take an asset_id and an Asset object as parameters and update the row in the database that matches the asset_id. 10 | # The delete method should take an asset_id as a parameter and delete the row in the database that matches the asset_id. 11 | # Create, update, and detele methods should return the updated Asset object. 12 | 13 | from itam.domain.asset import Asset 14 | from itam.infrastructure.ports.asset_database_port import AssetDatabasePort 15 | from sqlalchemy.orm import Session 16 | 17 | class AssetDatabaseAdapter(AssetDatabasePort): 18 | def __init__(self, session: Session): 19 | self._session = session 20 | 21 | def get_asset(self, asset_id: int) -> Asset: 22 | return self._session.query(Asset).filter(Asset.id == asset_id).first() 23 | 24 | def get_assets(self) -> list: 25 | return self._session.query(Asset).all() 26 | 27 | def create(self, asset: Asset) -> Asset: 28 | self._session.add(asset) 29 | self._session.commit() 30 | return asset 31 | 32 | def update(self, asset_id: int, asset: Asset) -> Asset: 33 | self._session.query(Asset).filter(Asset.id == asset_id).update(asset) 34 | self._session.commit() 35 | return asset 36 | 37 | def delete(self, asset_id: int) -> None: 38 | self._session.query(Asset).filter(Asset.id == asset_id).delete() 39 | self._session.commit() 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /chapter_5/itam/infrastructure/adapters/asset_database_adapter.py: -------------------------------------------------------------------------------- 1 | # Create a class called AssetDatabaseAdapter that implements the DatabasePort interface 2 | # This class will handle the database operations using a SQLAlchemy session. 3 | # The adapter should interact with Asset. 4 | # Implement methods for creating, getting, updating, and deleting assets, as well as listing all assets. 5 | # The adapter should not interact with the domain model directly. 6 | # The get_asset method should return a single Asset based off of the asset_id parameter. 7 | # The get_assets method should return a list of all assets from the database. 8 | # The create method should take an Asset object as a parameter and create a new row in the database as well as return the new Asset object. 9 | # The update method should take an asset_id and an Asset object as parameters and update the row in the database that matches the asset_id. 10 | # The delete method should take an asset_id as a parameter and delete the row in the database that matches the asset_id. 11 | # Create, update, and detele methods should return the updated Asset object. 12 | 13 | from itam.domain.asset import Asset 14 | from itam.infrastructure.ports.asset_database_port import AssetDatabasePort 15 | from sqlalchemy.orm import Session 16 | 17 | class AssetDatabaseAdapter(AssetDatabasePort): 18 | def __init__(self, session: Session): 19 | self._session = session 20 | 21 | def get_asset(self, asset_id: int) -> Asset: 22 | return self._session.query(Asset).filter(Asset.id == asset_id).first() 23 | 24 | def get_assets(self) -> list: 25 | return self._session.query(Asset).all() 26 | 27 | def create(self, asset: Asset) -> Asset: 28 | self._session.add(asset) 29 | self._session.commit() 30 | return asset 31 | 32 | def update(self, asset_id: int, asset: Asset) -> Asset: 33 | self._session.query(Asset).filter(Asset.id == asset_id).update(asset) 34 | self._session.commit() 35 | return asset 36 | 37 | def delete(self, asset_id: int) -> None: 38 | self._session.query(Asset).filter(Asset.id == asset_id).delete() 39 | self._session.commit() 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /chapter_6/itam/infrastructure/adapters/asset_database_adapter.py: -------------------------------------------------------------------------------- 1 | # Create a class called AssetDatabaseAdapter that implements the DatabasePort interface 2 | # This class will handle the database operations using a SQLAlchemy session. 3 | # The adapter should interact with Asset. 4 | # Implement methods for creating, getting, updating, and deleting assets, as well as listing all assets. 5 | # The adapter should not interact with the domain model directly. 6 | # The get_asset method should return a single Asset based off of the asset_id parameter. 7 | # The get_assets method should return a list of all assets from the database. 8 | # The create method should take an Asset object as a parameter and create a new row in the database as well as return the new Asset object. 9 | # The update method should take an asset_id and an Asset object as parameters and update the row in the database that matches the asset_id. 10 | # The delete method should take an asset_id as a parameter and delete the row in the database that matches the asset_id. 11 | # Create, update, and detele methods should return the updated Asset object. 12 | 13 | from itam.domain.asset import Asset 14 | from itam.infrastructure.ports.asset_database_port import AssetDatabasePort 15 | from sqlalchemy.orm import Session 16 | 17 | class AssetDatabaseAdapter(AssetDatabasePort): 18 | def __init__(self, session: Session): 19 | self._session = session 20 | 21 | def get_asset(self, asset_id: int) -> Asset: 22 | return self._session.query(Asset).filter(Asset.id == asset_id).first() 23 | 24 | def get_assets(self) -> list: 25 | return self._session.query(Asset).all() 26 | 27 | def create(self, asset: Asset) -> Asset: 28 | self._session.add(asset) 29 | self._session.commit() 30 | return asset 31 | 32 | def update(self, asset_id: int, asset: Asset) -> Asset: 33 | self._session.query(Asset).filter(Asset.id == asset_id).update(asset) 34 | self._session.commit() 35 | return asset 36 | 37 | def delete(self, asset_id: int) -> None: 38 | self._session.query(Asset).filter(Asset.id == asset_id).delete() 39 | self._session.commit() 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /chapter_7/itam/infrastructure/adapters/asset_database_adapter.py: -------------------------------------------------------------------------------- 1 | # Create a class called AssetDatabaseAdapter that implements the DatabasePort interface 2 | # This class will handle the database operations using a SQLAlchemy session. 3 | # The adapter should interact with Asset. 4 | # Implement methods for creating, getting, updating, and deleting assets, as well as listing all assets. 5 | # The adapter should not interact with the domain model directly. 6 | # The get_asset method should return a single Asset based off of the asset_id parameter. 7 | # The get_assets method should return a list of all assets from the database. 8 | # The create method should take an Asset object as a parameter and create a new row in the database as well as return the new Asset object. 9 | # The update method should take an asset_id and an Asset object as parameters and update the row in the database that matches the asset_id. 10 | # The delete method should take an asset_id as a parameter and delete the row in the database that matches the asset_id. 11 | # Create, update, and detele methods should return the updated Asset object. 12 | 13 | from itam.domain.asset import Asset 14 | from itam.infrastructure.ports.asset_database_port import AssetDatabasePort 15 | from sqlalchemy.orm import Session 16 | 17 | class AssetDatabaseAdapter(AssetDatabasePort): 18 | def __init__(self, session: Session): 19 | self._session = session 20 | 21 | def get_asset(self, asset_id: int) -> Asset: 22 | return self._session.query(Asset).filter(Asset.id == asset_id).first() 23 | 24 | def get_assets(self) -> list: 25 | return self._session.query(Asset).all() 26 | 27 | def create(self, asset: Asset) -> Asset: 28 | self._session.add(asset) 29 | self._session.commit() 30 | return asset 31 | 32 | def update(self, asset_id: int, asset: Asset) -> Asset: 33 | self._session.query(Asset).filter(Asset.id == asset_id).update(asset) 34 | self._session.commit() 35 | return asset 36 | 37 | def delete(self, asset_id: int) -> None: 38 | self._session.query(Asset).filter(Asset.id == asset_id).delete() 39 | self._session.commit() 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /chapter_4/itam/domain/software.py: -------------------------------------------------------------------------------- 1 | # create a class called Software, which is an instance of Asset. The Software entity has the following attributes: 2 | # - id: int, 3 | # - name: str 4 | # - version: str 5 | # - license_key: str 6 | # - vendor: str 7 | # - status: str 8 | # - department_percentages: Dict[Department, float] 9 | # none of the attributes can be None 10 | # define two methods specific to the Software entity: get_department_cost() and calculate_depreciation(). The get_department_cost() method calculates the cost of the asset for a given department, based on the percentages assigned to each department in the get_department_cost attribute. The calculate_depreciation() method calculates the depreciation of the asset using a given depreciation strategy. 11 | # automatically generates special methods for a class that are commonly used for data objects 12 | 13 | from typing import Dict 14 | from dataclasses import dataclass 15 | from itam.domain.department import Department 16 | from itam.domain.depreciation_strategy import DepreciationStrategy 17 | from itam.domain.asset import Asset 18 | 19 | @dataclass 20 | class Software(Asset): 21 | name: str 22 | version: str 23 | license_key: str 24 | vendor: str 25 | status: str 26 | department_percentages: Dict[Department, float] 27 | 28 | def __post_init__(self): 29 | if self.name is None: 30 | raise TypeError("Name cannot be None") 31 | if self.version is None: 32 | raise TypeError("Version cannot be None") 33 | if self.license_key is None: 34 | raise TypeError("License Key cannot be None") 35 | if self.vendor is None: 36 | raise TypeError("Vendor cannot be None") 37 | if self.status is None: 38 | raise TypeError("Status cannot be None") 39 | if self.department_percentages is None: 40 | raise TypeError("Line of Department Percentages cannot be None") 41 | 42 | def get_department_cost(self, department: Department) -> float: 43 | return self.cost * self.department_percentages[department] 44 | 45 | def calculate_depreciation(self, depreciation_strategy: DepreciationStrategy) -> float: 46 | return depreciation_strategy.calculate_depreciation(self.cost, self.purchase_date) -------------------------------------------------------------------------------- /chapter_5/itam/domain/software.py: -------------------------------------------------------------------------------- 1 | # create a class called Software, which is an instance of Asset. The Software entity has the following attributes: 2 | # - id: int, 3 | # - name: str 4 | # - version: str 5 | # - license_key: str 6 | # - vendor: str 7 | # - status: str 8 | # - department_percentages: Dict[Department, float] 9 | # none of the attributes can be None 10 | # define two methods specific to the Software entity: get_department_cost() and calculate_depreciation(). The get_department_cost() method calculates the cost of the asset for a given department, based on the percentages assigned to each department in the get_department_cost attribute. The calculate_depreciation() method calculates the depreciation of the asset using a given depreciation strategy. 11 | # automatically generates special methods for a class that are commonly used for data objects 12 | 13 | from typing import Dict 14 | from dataclasses import dataclass 15 | from itam.domain.department import Department 16 | from itam.domain.depreciation_strategy import DepreciationStrategy 17 | from itam.domain.asset import Asset 18 | 19 | @dataclass 20 | class Software(Asset): 21 | name: str 22 | version: str 23 | license_key: str 24 | vendor: str 25 | status: str 26 | department_percentages: Dict[Department, float] 27 | 28 | def __post_init__(self): 29 | if self.name is None: 30 | raise TypeError("Name cannot be None") 31 | if self.version is None: 32 | raise TypeError("Version cannot be None") 33 | if self.license_key is None: 34 | raise TypeError("License Key cannot be None") 35 | if self.vendor is None: 36 | raise TypeError("Vendor cannot be None") 37 | if self.status is None: 38 | raise TypeError("Status cannot be None") 39 | if self.department_percentages is None: 40 | raise TypeError("Line of Department Percentages cannot be None") 41 | 42 | def get_department_cost(self, department: Department) -> float: 43 | return self.cost * self.department_percentages[department] 44 | 45 | def calculate_depreciation(self, depreciation_strategy: DepreciationStrategy) -> float: 46 | return depreciation_strategy.calculate_depreciation(self.cost, self.purchase_date) -------------------------------------------------------------------------------- /chapter_6/itam/domain/software.py: -------------------------------------------------------------------------------- 1 | # create a class called Software, which is an instance of Asset. The Software entity has the following attributes: 2 | # - id: int, 3 | # - name: str 4 | # - version: str 5 | # - license_key: str 6 | # - vendor: str 7 | # - status: str 8 | # - department_percentages: Dict[Department, float] 9 | # none of the attributes can be None 10 | # define two methods specific to the Software entity: get_department_cost() and calculate_depreciation(). The get_department_cost() method calculates the cost of the asset for a given department, based on the percentages assigned to each department in the get_department_cost attribute. The calculate_depreciation() method calculates the depreciation of the asset using a given depreciation strategy. 11 | # automatically generates special methods for a class that are commonly used for data objects 12 | 13 | from typing import Dict 14 | from dataclasses import dataclass 15 | from itam.domain.department import Department 16 | from itam.domain.depreciation_strategy import DepreciationStrategy 17 | from itam.domain.asset import Asset 18 | 19 | @dataclass 20 | class Software(Asset): 21 | name: str 22 | version: str 23 | license_key: str 24 | vendor: str 25 | status: str 26 | department_percentages: Dict[Department, float] 27 | 28 | def __post_init__(self): 29 | if self.name is None: 30 | raise TypeError("Name cannot be None") 31 | if self.version is None: 32 | raise TypeError("Version cannot be None") 33 | if self.license_key is None: 34 | raise TypeError("License Key cannot be None") 35 | if self.vendor is None: 36 | raise TypeError("Vendor cannot be None") 37 | if self.status is None: 38 | raise TypeError("Status cannot be None") 39 | if self.department_percentages is None: 40 | raise TypeError("Line of Department Percentages cannot be None") 41 | 42 | def get_department_cost(self, department: Department) -> float: 43 | return self.cost * self.department_percentages[department] 44 | 45 | def calculate_depreciation(self, depreciation_strategy: DepreciationStrategy) -> float: 46 | return depreciation_strategy.calculate_depreciation(self.cost, self.purchase_date) -------------------------------------------------------------------------------- /chapter_7/itam/domain/software.py: -------------------------------------------------------------------------------- 1 | # create a class called Software, which is an instance of Asset. The Software entity has the following attributes: 2 | # - id: int, 3 | # - name: str 4 | # - version: str 5 | # - license_key: str 6 | # - vendor: str 7 | # - status: str 8 | # - department_percentages: Dict[Department, float] 9 | # none of the attributes can be None 10 | # define two methods specific to the Software entity: get_department_cost() and calculate_depreciation(). The get_department_cost() method calculates the cost of the asset for a given department, based on the percentages assigned to each department in the get_department_cost attribute. The calculate_depreciation() method calculates the depreciation of the asset using a given depreciation strategy. 11 | # automatically generates special methods for a class that are commonly used for data objects 12 | 13 | from typing import Dict 14 | from dataclasses import dataclass 15 | from itam.domain.department import Department 16 | from itam.domain.depreciation_strategy import DepreciationStrategy 17 | from itam.domain.asset import Asset 18 | 19 | @dataclass 20 | class Software(Asset): 21 | name: str 22 | version: str 23 | license_key: str 24 | vendor: str 25 | status: str 26 | department_percentages: Dict[Department, float] 27 | 28 | def __post_init__(self): 29 | if self.name is None: 30 | raise TypeError("Name cannot be None") 31 | if self.version is None: 32 | raise TypeError("Version cannot be None") 33 | if self.license_key is None: 34 | raise TypeError("License Key cannot be None") 35 | if self.vendor is None: 36 | raise TypeError("Vendor cannot be None") 37 | if self.status is None: 38 | raise TypeError("Status cannot be None") 39 | if self.department_percentages is None: 40 | raise TypeError("Line of Department Percentages cannot be None") 41 | 42 | def get_department_cost(self, department: Department) -> float: 43 | return self.cost * self.department_percentages[department] 44 | 45 | def calculate_depreciation(self, depreciation_strategy: DepreciationStrategy) -> float: 46 | return depreciation_strategy.calculate_depreciation(self.cost, self.purchase_date) -------------------------------------------------------------------------------- /chapter_4/itam/domain/depreciation_strategy.py: -------------------------------------------------------------------------------- 1 | # Define an interface called DepreciationStrategy. 2 | # It should have four concrete implementations of the interface: StraightLineDepreciationStrategy, DecliningBalanceDepreciationStrategy, DoubleDecliningDepreciationStrategy, and NoDepreciationStrategy. 3 | # Each implementation overrides the calculate_depreciation() method to provide a specific way of calculating depreciation for an asset based on its funding details. 4 | # The calculate_depreciation() method should take a FundingDetails object as a parameter and return a float value representing the depreciation amount. 5 | # NoDepreciationStrategy should return 0 for all assets. 6 | # The other three strategies should return the depreciation amount based on the following formulas: 7 | # - Straight Line: (cost - salvage value) / useful_life 8 | # - Declining Balance: cost * (1-rate/100)^(current_year - purchase_year) 9 | # - Double Declining: Declining Balance * 2 10 | 11 | from abc import ABC, abstractmethod 12 | from itam.domain.asset import Asset 13 | from math import pow 14 | from datetime import datetime 15 | 16 | class DepreciationStrategy(ABC): 17 | @abstractmethod 18 | def calculate_depreciation(self, asset: Asset) -> float: 19 | pass 20 | 21 | class StraightLineDepreciationStrategy(DepreciationStrategy): 22 | def calculate_depreciation(self, asset: Asset) -> float: 23 | cost = asset.get_cost() 24 | salvage_value = asset.get_salvage_value() 25 | useful_life = asset.get_useful_life() 26 | return (cost - salvage_value) / useful_life 27 | 28 | class DecliningBalanceDepreciationStrategy(DepreciationStrategy): 29 | def calculate_depreciation(self, asset: Asset) -> float: 30 | cost = asset.get_cost() 31 | depreciation_rate = asset.get_depreciation_rate() 32 | return cost * pow(1 - (depreciation_rate / 100), datetime.now().year - asset.get_purchase_date().year) 33 | 34 | class DoubleDecliningDepreciationStrategy(DepreciationStrategy): 35 | def calculate_depreciation(self, asset: Asset) -> float: 36 | return DecliningBalanceDepreciationStrategy().calculate_depreciation(asset) * 2 37 | 38 | class NoDepreciationStrategy(DepreciationStrategy): 39 | def calculate_depreciation(self, asset: Asset) -> float: 40 | return 0 -------------------------------------------------------------------------------- /chapter_5/itam/domain/depreciation_strategy.py: -------------------------------------------------------------------------------- 1 | # Define an interface called DepreciationStrategy. 2 | # It should have four concrete implementations of the interface: StraightLineDepreciationStrategy, DecliningBalanceDepreciationStrategy, DoubleDecliningDepreciationStrategy, and NoDepreciationStrategy. 3 | # Each implementation overrides the calculate_depreciation() method to provide a specific way of calculating depreciation for an asset based on its funding details. 4 | # The calculate_depreciation() method should take a FundingDetails object as a parameter and return a float value representing the depreciation amount. 5 | # NoDepreciationStrategy should return 0 for all assets. 6 | # The other three strategies should return the depreciation amount based on the following formulas: 7 | # - Straight Line: (cost - salvage value) / useful_life 8 | # - Declining Balance: cost * (1-rate/100)^(current_year - purchase_year) 9 | # - Double Declining: Declining Balance * 2 10 | 11 | from abc import ABC, abstractmethod 12 | from itam.domain.asset import Asset 13 | from math import pow 14 | from datetime import datetime 15 | 16 | class DepreciationStrategy(ABC): 17 | @abstractmethod 18 | def calculate_depreciation(self, asset: Asset) -> float: 19 | pass 20 | 21 | class StraightLineDepreciationStrategy(DepreciationStrategy): 22 | def calculate_depreciation(self, asset: Asset) -> float: 23 | cost = asset.get_cost() 24 | salvage_value = asset.get_salvage_value() 25 | useful_life = asset.get_useful_life() 26 | return (cost - salvage_value) / useful_life 27 | 28 | class DecliningBalanceDepreciationStrategy(DepreciationStrategy): 29 | def calculate_depreciation(self, asset: Asset) -> float: 30 | cost = asset.get_cost() 31 | depreciation_rate = asset.get_depreciation_rate() 32 | return cost * pow(1 - (depreciation_rate / 100), datetime.now().year - asset.get_purchase_date().year) 33 | 34 | class DoubleDecliningDepreciationStrategy(DepreciationStrategy): 35 | def calculate_depreciation(self, asset: Asset) -> float: 36 | return DecliningBalanceDepreciationStrategy().calculate_depreciation(asset) * 2 37 | 38 | class NoDepreciationStrategy(DepreciationStrategy): 39 | def calculate_depreciation(self, asset: Asset) -> float: 40 | return 0 -------------------------------------------------------------------------------- /chapter_4/itam/domain/hardware.py: -------------------------------------------------------------------------------- 1 | # Define a class called Hardware, which is an instance of Asset. 2 | # The Hardware entity has the following attributes: 3 | # - serial_number: str, 4 | # - location: Location, 5 | # - warranty_expiration_date: date, 6 | # - notes: str 7 | # - maintenance_schedules: List[MaintenanceSchedule] 8 | # - warranty: Warranty 9 | # - retirement_date: date 10 | # - retirement_reason: str 11 | # - usage_statistics: UsageStatistics 12 | # - budget: Budget 13 | # The attributes can be None and the class should have a constructor that takes all attributes as parameters. 14 | # The attributes should be private and the class should have accessor methods for all attributes. 15 | 16 | from datetime import datetime 17 | from itam.domain.asset import Asset 18 | from itam.domain.location import Location 19 | from itam.domain.warranty import Warranty 20 | from itam.domain.maintenance_schedule import MaintenanceSchedule 21 | from itam.domain.usage_statistics import UsageStatistics 22 | from itam.domain.budget import Budget 23 | 24 | class Hardware(Asset): 25 | serial_number: str 26 | location: Location 27 | warranty_expiration_date: datetime 28 | notes: str 29 | maintenance_schedules: list[MaintenanceSchedule] 30 | warranty: Warranty 31 | retirement_date: datetime 32 | retirement_reason: str 33 | usage_statistics: UsageStatistics 34 | budget: Budget 35 | 36 | def get_serial_number(self) -> str: 37 | return self.serial_number 38 | 39 | def get_location(self) -> Location: 40 | return self.location 41 | 42 | def get_warranty_expiration_date(self) -> datetime: 43 | return self.warranty_expiration_date 44 | 45 | def get_notes(self) -> str: 46 | return self.notes 47 | 48 | def get_maintenance_schedules(self) -> list[MaintenanceSchedule]: 49 | return self.maintenance_schedules 50 | 51 | def get_warranty(self) -> Warranty: 52 | return self.warranty 53 | 54 | def get_retirement_date(self) -> datetime: 55 | return self.retirement_date 56 | 57 | def get_retirement_reason(self) -> str: 58 | return self.retirement_reason 59 | 60 | def get_usage_statistics(self) -> UsageStatistics: 61 | return self.usage_statistics 62 | 63 | def get_budget(self) -> Budget: 64 | return self.budget 65 | 66 | -------------------------------------------------------------------------------- /chapter_5/itam/domain/hardware.py: -------------------------------------------------------------------------------- 1 | # Define a class called Hardware, which is an instance of Asset. 2 | # The Hardware entity has the following attributes: 3 | # - serial_number: str, 4 | # - location: Location, 5 | # - warranty_expiration_date: date, 6 | # - notes: str 7 | # - maintenance_schedules: List[MaintenanceSchedule] 8 | # - warranty: Warranty 9 | # - retirement_date: date 10 | # - retirement_reason: str 11 | # - usage_statistics: UsageStatistics 12 | # - budget: Budget 13 | # The attributes can be None and the class should have a constructor that takes all attributes as parameters. 14 | # The attributes should be private and the class should have accessor methods for all attributes. 15 | 16 | from datetime import datetime 17 | from itam.domain.asset import Asset 18 | #from itam.domain.location import Location 19 | from itam.domain.warranty import Warranty 20 | from itam.domain.maintenance_schedule import MaintenanceSchedule 21 | from itam.domain.usage_statistics import UsageStatistics 22 | from itam.domain.budget import Budget 23 | 24 | class Hardware(Asset): 25 | serial_number: str 26 | #location: Location 27 | warranty_expiration_date: datetime 28 | notes: str 29 | maintenance_schedules: list[MaintenanceSchedule] 30 | warranty: Warranty 31 | retirement_date: datetime 32 | retirement_reason: str 33 | usage_statistics: UsageStatistics 34 | budget: Budget 35 | 36 | def get_serial_number(self) -> str: 37 | return self.serial_number 38 | 39 | #def get_location(self) -> Location: 40 | # return self.location 41 | 42 | def get_warranty_expiration_date(self) -> datetime: 43 | return self.warranty_expiration_date 44 | 45 | def get_notes(self) -> str: 46 | return self.notes 47 | 48 | def get_maintenance_schedules(self) -> list[MaintenanceSchedule]: 49 | return self.maintenance_schedules 50 | 51 | def get_warranty(self) -> Warranty: 52 | return self.warranty 53 | 54 | def get_retirement_date(self) -> datetime: 55 | return self.retirement_date 56 | 57 | def get_retirement_reason(self) -> str: 58 | return self.retirement_reason 59 | 60 | def get_usage_statistics(self) -> UsageStatistics: 61 | return self.usage_statistics 62 | 63 | def get_budget(self) -> Budget: 64 | return self.budget 65 | 66 | -------------------------------------------------------------------------------- /chapter_6/itam/domain/hardware.py: -------------------------------------------------------------------------------- 1 | # Define a class called Hardware, which is an instance of Asset. 2 | # The Hardware entity has the following attributes: 3 | # - serial_number: str, 4 | # - location: Location, 5 | # - warranty_expiration_date: date, 6 | # - notes: str 7 | # - maintenance_schedules: List[MaintenanceSchedule] 8 | # - warranty: Warranty 9 | # - retirement_date: date 10 | # - retirement_reason: str 11 | # - usage_statistics: UsageStatistics 12 | # - budget: Budget 13 | # The attributes can be None and the class should have a constructor that takes all attributes as parameters. 14 | # The attributes should be private and the class should have accessor methods for all attributes. 15 | 16 | from datetime import datetime 17 | from itam.domain.asset import Asset 18 | #from itam.domain.location import Location 19 | from itam.domain.warranty import Warranty 20 | from itam.domain.maintenance_schedule import MaintenanceSchedule 21 | from itam.domain.usage_statistics import UsageStatistics 22 | from itam.domain.budget import Budget 23 | 24 | class Hardware(Asset): 25 | serial_number: str 26 | #location: Location 27 | warranty_expiration_date: datetime 28 | notes: str 29 | maintenance_schedules: list[MaintenanceSchedule] 30 | warranty: Warranty 31 | retirement_date: datetime 32 | retirement_reason: str 33 | usage_statistics: UsageStatistics 34 | budget: Budget 35 | 36 | def get_serial_number(self) -> str: 37 | return self.serial_number 38 | 39 | #def get_location(self) -> Location: 40 | # return self.location 41 | 42 | def get_warranty_expiration_date(self) -> datetime: 43 | return self.warranty_expiration_date 44 | 45 | def get_notes(self) -> str: 46 | return self.notes 47 | 48 | def get_maintenance_schedules(self) -> list[MaintenanceSchedule]: 49 | return self.maintenance_schedules 50 | 51 | def get_warranty(self) -> Warranty: 52 | return self.warranty 53 | 54 | def get_retirement_date(self) -> datetime: 55 | return self.retirement_date 56 | 57 | def get_retirement_reason(self) -> str: 58 | return self.retirement_reason 59 | 60 | def get_usage_statistics(self) -> UsageStatistics: 61 | return self.usage_statistics 62 | 63 | def get_budget(self) -> Budget: 64 | return self.budget 65 | 66 | -------------------------------------------------------------------------------- /chapter_7/itam/domain/hardware.py: -------------------------------------------------------------------------------- 1 | # Define a class called Hardware, which is an instance of Asset. 2 | # The Hardware entity has the following attributes: 3 | # - serial_number: str, 4 | # - location: Location, 5 | # - warranty_expiration_date: date, 6 | # - notes: str 7 | # - maintenance_schedules: List[MaintenanceSchedule] 8 | # - warranty: Warranty 9 | # - retirement_date: date 10 | # - retirement_reason: str 11 | # - usage_statistics: UsageStatistics 12 | # - budget: Budget 13 | # The attributes can be None and the class should have a constructor that takes all attributes as parameters. 14 | # The attributes should be private and the class should have accessor methods for all attributes. 15 | 16 | from datetime import datetime 17 | from itam.domain.asset import Asset 18 | #from itam.domain.location import Location 19 | from itam.domain.warranty import Warranty 20 | from itam.domain.maintenance_schedule import MaintenanceSchedule 21 | from itam.domain.usage_statistics import UsageStatistics 22 | from itam.domain.budget import Budget 23 | 24 | class Hardware(Asset): 25 | serial_number: str 26 | #location: Location 27 | warranty_expiration_date: datetime 28 | notes: str 29 | maintenance_schedules: list[MaintenanceSchedule] 30 | warranty: Warranty 31 | retirement_date: datetime 32 | retirement_reason: str 33 | usage_statistics: UsageStatistics 34 | budget: Budget 35 | 36 | def get_serial_number(self) -> str: 37 | return self.serial_number 38 | 39 | #def get_location(self) -> Location: 40 | # return self.location 41 | 42 | def get_warranty_expiration_date(self) -> datetime: 43 | return self.warranty_expiration_date 44 | 45 | def get_notes(self) -> str: 46 | return self.notes 47 | 48 | def get_maintenance_schedules(self) -> list[MaintenanceSchedule]: 49 | return self.maintenance_schedules 50 | 51 | def get_warranty(self) -> Warranty: 52 | return self.warranty 53 | 54 | def get_retirement_date(self) -> datetime: 55 | return self.retirement_date 56 | 57 | def get_retirement_reason(self) -> str: 58 | return self.retirement_reason 59 | 60 | def get_usage_statistics(self) -> UsageStatistics: 61 | return self.usage_statistics 62 | 63 | def get_budget(self) -> Budget: 64 | return self.budget 65 | 66 | --------------------------------------------------------------------------------