diff --git a/hub/imports/geometry_factory.py b/hub/imports/geometry_factory.py index 736e4f65..fed3c30e 100644 --- a/hub/imports/geometry_factory.py +++ b/hub/imports/geometry_factory.py @@ -4,9 +4,9 @@ SPDX - License - Identifier: LGPL - 3.0 - or -later Copyright © 2022 Concordia CERC group Project Coder Guille Gutierrez guillermo.gutierrezmorote@concordia.ca """ - -import geopandas import logging +import geopandas + from hub.city_model_structure.city import City from hub.imports.geometry.citygml import CityGml from hub.imports.geometry.obj import Obj @@ -61,7 +61,7 @@ class GeometryFactory: :return: City """ return Obj(self._path).city - + @property def _gpandas(self) -> City: """ diff --git a/hub/imports/weather_factory.py b/hub/imports/weather_factory.py index 9d0b942d..1b8514ab 100644 --- a/hub/imports/weather_factory.py +++ b/hub/imports/weather_factory.py @@ -52,7 +52,3 @@ class WeatherFactory: :return: None """ getattr(self, self._handler, lambda: None)() - - def enrich_debug(self): - _path = Path(self._base_path / 'epw').resolve() - return EpwWeatherParameters(self._city, _path, self._file_name) diff --git a/hub/persistence/__init__.py b/hub/persistence/__init__.py index 19c4e0dc..b3ad9bc8 100644 --- a/hub/persistence/__init__.py +++ b/hub/persistence/__init__.py @@ -1,3 +1,7 @@ +""" +Persistence package +""" + from .repository import Repository from .repositories.city import City from .repositories.application import Application diff --git a/hub/persistence/configuration.py b/hub/persistence/configuration.py index a49e986d..a71ca59b 100644 --- a/hub/persistence/configuration.py +++ b/hub/persistence/configuration.py @@ -28,8 +28,9 @@ class Configuration: try: # load environmental variables if not Path(dotenv_path).exists(): - logging.error(f'dotenv file doesn\'t exists at {dotenv_path}') - raise FileNotFoundError(f'dotenv file doesn\'t exists at {dotenv_path}') + error_message = f'dotenv file doesn\'t exists at {dotenv_path}' + logging.error(error_message) + raise FileNotFoundError(error_message) load_dotenv(dotenv_path=dotenv_path) self._db_name = db_name @@ -39,7 +40,7 @@ class Configuration: self._db_port = os.getenv(f'{app_env}_DB_PORT') self.hub_token = os.getenv('HUB_TOKEN') except KeyError as err: - logging.error(f'Error with credentials: {err}') + logging.error('Error with credentials: %s', err) @property def connection_string(self): diff --git a/hub/persistence/db_setup.py b/hub/persistence/db_setup.py index f5324158..38a0764f 100644 --- a/hub/persistence/db_setup.py +++ b/hub/persistence/db_setup.py @@ -5,6 +5,7 @@ Copyright © 2022 Concordia CERC group Project Coder Peter Yefi peteryefi@gmail.com """ +import logging from hub.persistence import Repository from hub.persistence.models import Application from hub.persistence.models import City @@ -14,17 +15,21 @@ from hub.persistence.models import UserRoles from hub.persistence.models import SimulationResults from hub.persistence.repositories import User as UserRepository from hub.persistence.repositories import Application as ApplicationRepository -import logging class DBSetup: + """ + Creates a Persistence database structure + """ def __init__(self, db_name, app_env, dotenv_path, admin_password, application_uuid): """ Creates database tables a default admin user and a default admin app with the given password and uuid - :param db_name: - :param app_env: - :param dotenv_path: + :param db_name: database name + :param app_env: application environment type [TEST|PROD] + :param dotenv_path: .env file path + :param admin_password: administrator password for the application uuid + :application_uuid: application uuid """ repository = Repository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path) @@ -47,19 +52,19 @@ class DBSetup: logging.info('Creating default admin tool application...') application = application_repo.insert(name, description, application_uuid) - if type(application) is dict: + if isinstance(application, dict): logging.info(application) else: msg = f'Created Admin tool with application_uuid: {application_uuid}' logging.info(msg) - return application.id + return application.id @staticmethod def _create_admin_user(user_repo, admin_password, application_id): password = admin_password logging.info('Creating default admin user...') user = user_repo.insert('Administrator', password, UserRoles.Admin, application_id) - if type(user) is dict: + if isinstance(user, dict): logging.info(user) else: - logging.info(f'Created Admin user') + logging.info('Created Admin user') diff --git a/hub/persistence/models/__init__.py b/hub/persistence/models/__init__.py index 77f5c105..4682044f 100644 --- a/hub/persistence/models/__init__.py +++ b/hub/persistence/models/__init__.py @@ -1,3 +1,6 @@ +""" +Models package +""" from .application import Application from .city import City from .city_object import CityObject diff --git a/hub/persistence/models/city_object.py b/hub/persistence/models/city_object.py index 30b05323..d44e88c2 100644 --- a/hub/persistence/models/city_object.py +++ b/hub/persistence/models/city_object.py @@ -15,55 +15,55 @@ from hub.persistence.configuration import Models class CityObject(Models): - """ + """ A model representation of an application """ - __tablename__ = 'city_object' - id = Column(Integer, Sequence('city_object_id_seq'), primary_key=True) - city_id = Column(Integer, ForeignKey('city.id'), nullable=False) - name = Column(String, nullable=False) - alias = Column(String, nullable=True) - type = Column(String, nullable=False) - year_of_construction = Column(Integer, nullable=True) - function = Column(String, nullable=True) - usage = Column(String, nullable=True) - volume = Column(Float, nullable=False) - area = Column(Float, nullable=False) - total_heating_area = Column(Float, nullable=False) - wall_area = Column(Float, nullable=False) - windows_area = Column(Float, nullable=False) - system_name = Column(String, nullable=False) - created = Column(DateTime, default=datetime.datetime.utcnow) - updated = Column(DateTime, default=datetime.datetime.utcnow) + __tablename__ = 'city_object' + id = Column(Integer, Sequence('city_object_id_seq'), primary_key=True) + city_id = Column(Integer, ForeignKey('city.id'), nullable=False) + name = Column(String, nullable=False) + alias = Column(String, nullable=True) + type = Column(String, nullable=False) + year_of_construction = Column(Integer, nullable=True) + function = Column(String, nullable=True) + usage = Column(String, nullable=True) + volume = Column(Float, nullable=False) + area = Column(Float, nullable=False) + total_heating_area = Column(Float, nullable=False) + wall_area = Column(Float, nullable=False) + windows_area = Column(Float, nullable=False) + system_name = Column(String, nullable=False) + created = Column(DateTime, default=datetime.datetime.utcnow) + updated = Column(DateTime, default=datetime.datetime.utcnow) - # def __init__(self, city_id, name, alias, object_type, year_of_construction, function, usage, volume, area): - def __init__(self, city_id, building: Building): - self.city_id = city_id - self.name = building.name - self.alias = building.alias - self.type = building.type - self.year_of_construction = building.year_of_construction - self.function = building.function - self.usage = building.usages_percentage - self.volume = building.volume - self.area = building.floor_area - storeys = building.storeys_above_ground - if storeys is None: - print(building.average_storey_height) - storeys = building.max_height / building.average_storey_height - self.total_heating_area = building.floor_area * storeys - wall_area = 0 - for wall in building.walls: - wall_area += wall.solid_polygon.area - self.wall_area = wall_area - window_ratio = 0 - for internal_zone in building.internal_zones: - for thermal_zone in internal_zone.thermal_zones: - for thermal_boundary in thermal_zone.thermal_boundaries: - window_ratio = thermal_boundary.window_ratio - break - self.windows_area = wall_area * window_ratio - system_name = building.energy_systems_archetype_name - if system_name is None: - system_name = '' - self.system_name = system_name + # def __init__(self, city_id, name, alias, object_type, year_of_construction, function, usage, volume, area): + def __init__(self, city_id, building: Building): + self.city_id = city_id + self.name = building.name + self.alias = building.alias + self.type = building.type + self.year_of_construction = building.year_of_construction + self.function = building.function + self.usage = building.usages_percentage + self.volume = building.volume + self.area = building.floor_area + storeys = building.storeys_above_ground + if storeys is None: + print(building.average_storey_height) + storeys = building.max_height / building.average_storey_height + self.total_heating_area = building.floor_area * storeys + wall_area = 0 + for wall in building.walls: + wall_area += wall.solid_polygon.area + self.wall_area = wall_area + window_ratio = 0 + for internal_zone in building.internal_zones: + for thermal_zone in internal_zone.thermal_zones: + for thermal_boundary in thermal_zone.thermal_boundaries: + window_ratio = thermal_boundary.window_ratio + break + self.windows_area = wall_area * window_ratio + system_name = building.energy_systems_archetype_name + if system_name is None: + system_name = '' + self.system_name = system_name diff --git a/hub/persistence/models/user.py b/hub/persistence/models/user.py index a40ccece..7a45e0b5 100644 --- a/hub/persistence/models/user.py +++ b/hub/persistence/models/user.py @@ -15,6 +15,9 @@ from hub.persistence.configuration import Models class UserRoles(enum.Enum): + """ + User roles enum + """ Admin = 'Admin' Hub_Reader = 'Hub_Reader' diff --git a/hub/persistence/repositories/__init__.py b/hub/persistence/repositories/__init__.py index 158b8448..e2202d0d 100644 --- a/hub/persistence/repositories/__init__.py +++ b/hub/persistence/repositories/__init__.py @@ -1,2 +1,5 @@ +""" +Repositories Package +""" from .user import User from .application import Application diff --git a/hub/persistence/repositories/application.py b/hub/persistence/repositories/application.py index c139c373..84a908ab 100644 --- a/hub/persistence/repositories/application.py +++ b/hub/persistence/repositories/application.py @@ -16,6 +16,9 @@ from hub.persistence.models import Application as Model class Application(Repository): + """ + Application repository + """ _instance = None def __init__(self, db_name: str, dotenv_path: str, app_env: str): @@ -46,9 +49,8 @@ class Application(Repository): self.session.commit() return application except SQLAlchemyError as err: - logging.error(f'An error occurred while creating application: {err}') - else: - return {'message': f'An application with {application_uuid} application uuid, already exists'} + logging.error('An error occurred while creating application: %s', err) + return {'message': f'An error occurred while creating application {application_uuid}'} def update(self, application_uuid: str, name: str, description: str) -> Union[Dict, None]: """ @@ -64,8 +66,9 @@ class Application(Repository): ).update({'name': name, 'description': description, 'updated': datetime.datetime.utcnow()}) self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while updating application: {err}') + logging.error('Error while updating application %s', err) return {'message': 'Error occurred while updating application'} + return None def delete(self, application_uuid: str): """ @@ -78,7 +81,7 @@ class Application(Repository): self.session.flush() self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while deleting application: {err}') + logging.error('Error while deleting application: %s', err) def get_by_uuid(self, application_uuid: str) -> Union[Model, None]: """ @@ -86,12 +89,13 @@ class Application(Repository): :param application_uuid: the application uuid :return: Application with the provided application_uuid or None """ + result_set = None try: result_set = self.session.execute(select(Model).where( Model.application_uuid == application_uuid) ).first() - if result_set is None: - return None - return result_set[0] except SQLAlchemyError as err: - logging.error(f'Error while fetching application by application_uuid: {err}') + logging.error('Error while fetching application by application_uuid: %s', err) + if result_set is None: + return None + return result_set[0] diff --git a/hub/persistence/repositories/city.py b/hub/persistence/repositories/city.py index b2fbbf21..b388f8a2 100644 --- a/hub/persistence/repositories/city.py +++ b/hub/persistence/repositories/city.py @@ -6,7 +6,7 @@ Project Coder Peter Yefi peteryefi@gmail.com """ import logging import datetime -from typing import Union, Dict +from typing import Union from sqlalchemy import select from sqlalchemy.exc import SQLAlchemyError @@ -19,6 +19,9 @@ from hub.version import __version__ class City(Repository): + """ + City repository + """ _instance = None def __init__(self, db_name: str, dotenv_path: str, app_env: str): @@ -32,14 +35,14 @@ class City(Repository): cls._instance = super(City, cls).__new__(cls) return cls._instance - def insert(self, city: CityHub, pickle_path, application_id, user_id: int) -> Union[Model, Dict]: + def insert(self, city: CityHub, pickle_path, application_id, user_id: int) -> Union[Model, None]: """ Inserts a city :param city: The complete city instance :param pickle_path: Path to the pickle :param application_id: Application id owning the instance :param user_id: User id owning the instance - :return: City and Dictionary + :return: City and None """ city.save_compressed(pickle_path) try: @@ -63,7 +66,8 @@ class City(Repository): self.session.commit() return db_city except SQLAlchemyError as err: - logging.error(f'An error occurred while creating city: {err}') + logging.error('An error occurred while creating city: %s', err) + return None def update(self, city_id: int, city: CityHub): """ @@ -74,11 +78,10 @@ class City(Repository): """ try: now = datetime.datetime.utcnow() - print(f'{now}') self.session.query(Model).filter(Model.id == city_id).update({'name': city.name, 'updated': now}) self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while updating city: {err}') + logging.error('Error while updating city: %s', err) def delete(self, city_id: int): """ @@ -91,7 +94,7 @@ class City(Repository): self.session.query(Model).filter(Model.id == city_id).delete() self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while fetching city: {err}') + logging.error('Error while fetching city: %s', err) def get_by_user_id_application_id_and_name(self, user_id, application_id, city_name): """ @@ -110,7 +113,8 @@ class City(Repository): result_set = result_set[0] return result_set except SQLAlchemyError as err: - logging.error(f'Error while fetching city by name: {err}') + logging.error('Error while fetching city by name: %s', err) + return None def get_by_user_id_and_application_id(self, user_id, application_id) -> [Model]: """ @@ -125,4 +129,5 @@ class City(Repository): ) return [r[0] for r in result_set] except SQLAlchemyError as err: - logging.error(f'Error while fetching city by name: {err}') + logging.error('Error while fetching city by name: %s', err) + return None diff --git a/hub/persistence/repositories/city_object.py b/hub/persistence/repositories/city_object.py index 6e0762ba..139b6ae4 100644 --- a/hub/persistence/repositories/city_object.py +++ b/hub/persistence/repositories/city_object.py @@ -45,11 +45,12 @@ class CityObject(Repository): self.session.add(city_object) self.session.flush() self.session.commit() - return city_object + except SQLAlchemyError as err: - logging.error(f'An error occurred while creating city_object: {err}') + logging.error('An error occurred while creating city_object: %s', err) else: return {'message': f'A city_object named {building.name} already exists in that city'} + return city_object def update(self, city_id: int, building: Building) -> Union[Dict, None]: """ @@ -76,8 +77,9 @@ class CityObject(Repository): 'updated': datetime.datetime.utcnow()}) self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while updating city object: {err}') + logging.error('Error while updating city object: %s', err) return {'message': 'Error occurred while updating application'} + return None def delete(self, city_id: int, name: str): """ @@ -90,7 +92,7 @@ class CityObject(Repository): self.session.query(Model).filter(Model.city_id == city_id, Model.name == name).delete() self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while deleting application: {err}') + logging.error('Error while deleting application: %s', err) def get_by_name_and_city(self, name, city_id) -> Union[Model, None]: """ @@ -99,13 +101,13 @@ class CityObject(Repository): :param city_id: a city identifier :return: [CityObject] with the provided name belonging to the city with id city_id """ + _city_object = None try: _city_object = self.session.execute(select(Model).where( Model.name == name, Model.city_id == city_id )).first() - if _city_object is None: - return None - return _city_object[0] except SQLAlchemyError as err: - print(err) - logging.error(f'Error while fetching application by application_uuid: {err}') + logging.error('Error while fetching application by application_uuid: %s', err) + if _city_object is None: + return None + return _city_object[0] diff --git a/hub/persistence/repositories/simulation_results.py b/hub/persistence/repositories/simulation_results.py index fc4f1d09..61ed85ad 100644 --- a/hub/persistence/repositories/simulation_results.py +++ b/hub/persistence/repositories/simulation_results.py @@ -19,6 +19,9 @@ from hub.persistence.models import SimulationResults as Model class SimulationResults(Repository): + """ + Simulation results repository + """ _instance = None def __init__(self, db_name: str, dotenv_path: str, app_env: str): @@ -44,11 +47,11 @@ class SimulationResults(Repository): if city_id is not None: city = self._get_city(city_id) if city is None: - return {'message': f'City does not exists'} + return {'message': 'City does not exists'} else: city_object = self._get_city_object(city_object_id) if city_object is None: - return {'message': f'City object does not exists'} + return {'message': 'City object does not exists'} try: simulation_result = Model(name=name, values=values, @@ -59,7 +62,9 @@ class SimulationResults(Repository): self.session.commit() return simulation_result except SQLAlchemyError as err: - logging.error(f'An error occurred while creating city_object: {err}') + error_message = f'An error occurred while creating city_object: {err}' + logging.error(error_message) + return {'message': error_message} def update(self, name: str, values: str, city_id=None, city_object_id=None) -> Union[Dict, None]: """ @@ -88,17 +93,19 @@ class SimulationResults(Repository): else: return {'message': 'Missing either city_id or city_object_id'} except SQLAlchemyError as err: - logging.error(f'Error while updating city object: {err}') - return {'message': 'Error occurred while updating application'} + error_message = f'Error while updating city object: {err}' + logging.error(error_message) + return {'message': error_message} + return None - def delete(self, name: str, city_id=None, city_object_id=None): + def delete(self, name: str, city_id=None, city_object_id=None) -> Union[Dict, None]: """ Deletes an application with the application_uuid :param name: The simulation results tool and workflow name :param city_id: The id for the city owning the simulation results :param city_object_id: the id for the city_object owning these simulation results - :return: None + :return: [Dict, None] """ try: if city_id is not None: @@ -110,9 +117,10 @@ class SimulationResults(Repository): else: return {'message': 'Missing either city_id or city_object_id'} except SQLAlchemyError as err: - logging.error(f'Error while deleting application: {err}') + logging.error('Error while deleting application: %s', err) + return None - def _get_city(self, city_id) -> [City]: + def _get_city(self, city_id) -> [City, None]: """ Fetch a city object based city id :param city_id: a city identifier @@ -121,7 +129,8 @@ class SimulationResults(Repository): try: return self.session.execute(select(City).where(City.id == city_id)).first() except SQLAlchemyError as err: - logging.error(f'Error while fetching city by city_id: {err}') + logging.error('Error while fetching city by city_id: %s', err) + return None def _get_city_object(self, city_object_id) -> [CityObject]: """ @@ -132,7 +141,8 @@ class SimulationResults(Repository): try: return self.session.execute(select(CityObject).where(CityObject.id == city_object_id)).first() except SQLAlchemyError as err: - logging.error(f'Error while fetching city by city_id: {err}') + logging.error('Error while fetching city by city_id: %s', err) + return None def get_simulation_results_by_city_id_city_object_id_and_names(self, city_id, city_object_id, result_names=None): """ @@ -156,4 +166,5 @@ class SimulationResults(Repository): _.append(result) return _ except SQLAlchemyError as err: - logging.error(f'Error while fetching city by city_id: {err}') + logging.error('Error while fetching city by city_id: %s', err) + return None diff --git a/hub/persistence/repositories/user.py b/hub/persistence/repositories/user.py index 8708cf3a..41e13cdd 100644 --- a/hub/persistence/repositories/user.py +++ b/hub/persistence/repositories/user.py @@ -5,18 +5,20 @@ Copyright © 2022 Concordia CERC group Project Coder Peter Yefi peteryefi@gmail.com """ import logging -from hub.persistence import Repository -from sqlalchemy.exc import SQLAlchemyError -from sqlalchemy import select -from hub.persistence.models import User as Model -from hub.persistence.models import Application as ApplicationModel -from hub.persistence.models import UserRoles -from hub.helpers.auth import Auth from typing import Union, Dict import datetime +from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy import select +from hub.persistence import Repository +from hub.persistence.models import User as Model, Application as ApplicationModel, UserRoles +from hub.helpers.auth import Auth + class User(Repository): + """ + User class + """ _instance = None def __init__(self, db_name: str, dotenv_path: str, app_env: str): @@ -48,9 +50,9 @@ class User(Repository): self.session.commit() return user except SQLAlchemyError as err: - logging.error(f'An error occurred while creating user: {err}') - else: - return {'message': f'user {name} already exists for that application'} + error_message = f'An error occurred while creating user: {err}' + logging.error(error_message) + return {'message': f'error creating user {name}'} def update(self, user_id: int, name: str, password: str, role: UserRoles) -> Union[Dict, None]: """ @@ -70,8 +72,9 @@ class User(Repository): }) self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while updating user: {err}') + logging.error('Error while updating user: %s', err) return {'err_msg': 'Error occurred while updated user'} + return None def delete(self, user_id: int): """ @@ -83,7 +86,7 @@ class User(Repository): self.session.query(Model).filter(Model.id == user_id).delete() self.session.commit() except SQLAlchemyError as err: - logging.error(f'Error while fetching user: {err}') + logging.error('Error while fetching user: %s', err) def get_by_name_and_application(self, name: str, application_id: int) -> Union[Model, None]: """ @@ -92,15 +95,16 @@ class User(Repository): :param application_id: User application name :return: User matching the search criteria or None """ + user = None try: user = self.session.execute( select(Model).where(Model.name == name, Model.application_id == application_id) ).first() if user is not None: user = user[0] - return user except SQLAlchemyError as err: - logging.error(f'Error while fetching user by name and application: {err}') + logging.error('Error while fetching user by name and application: %s', err) + return user def get_by_name_application_id_and_password(self, name: str, password: str, application_id: int) -> Union[Model, None]: """ @@ -118,7 +122,8 @@ class User(Repository): if Auth.check_password(password, user[0].password): return user[0] except SQLAlchemyError as err: - logging.error(f'Error while fetching user by email: {err}') + logging.error('Error while fetching user by email: %s', err) + return None def get_by_name_application_uuid_and_password(self, name: str, password: str, application_uuid: str) -> Union[Model, None]: """ @@ -128,10 +133,11 @@ class User(Repository): :param application_uuid: Application uuid :return: User """ + application = None try: application = self.session.execute( select(ApplicationModel).where(ApplicationModel.application_uuid == application_uuid) ).first() - return self.get_by_name_application_id_and_password(name, password, application[0].id) except SQLAlchemyError as err: - logging.error(f'Error while fetching user by name: {err}') + logging.error('Error while fetching user by name: %s', err) + return self.get_by_name_application_id_and_password(name, password, application[0].id) diff --git a/hub/persistence/repository.py b/hub/persistence/repository.py index dddbed94..6e0ae0bc 100644 --- a/hub/persistence/repository.py +++ b/hub/persistence/repository.py @@ -5,13 +5,16 @@ Copyright © 2022 Concordia CERC group Project Coder Peter Yefi peteryefi@gmail.com """ import logging - -from hub.persistence.configuration import Configuration from sqlalchemy import create_engine from sqlalchemy.orm import Session +from hub.persistence.configuration import Configuration + class Repository: + """ + Base repository class to establish db connection + """ def __init__(self, db_name, dotenv_path: str, app_env='TEST'): try: @@ -19,4 +22,4 @@ class Repository: self.engine = create_engine(self.configuration.connection_string) self.session = Session(self.engine) except ValueError as err: - logging.error(f'Missing value for credentials: {err}') + logging.error('Missing value for credentials: %s', err) diff --git a/hub/unittests/test_db_factory.py b/hub/unittests/test_db_factory.py index 5e0c117b..d7f78957 100644 --- a/hub/unittests/test_db_factory.py +++ b/hub/unittests/test_db_factory.py @@ -29,10 +29,10 @@ class Control: def __init__(self): """ -Test -setup -:return: None -""" + Test + setup + :return: None + """ self._skip_test = False # Create test database dotenv_path = Path("{}/.local/etc/hub/.env".format(os.path.expanduser('~'))).resolve() diff --git a/hub/version.py b/hub/version.py index 7a17ecc9..22d6010d 100644 --- a/hub/version.py +++ b/hub/version.py @@ -1 +1,4 @@ +""" +Hub version number +""" __version__ = '0.1.7.12'