From 5a6a259c97f816040d434e4dd5dddbca92555350 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 25 Nov 2021 10:50:28 +0100 Subject: [PATCH 01/22] Fixed scope of database session --- tests/conftest.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 5e49d55..af7deb4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,9 +7,15 @@ from ensysmod.database.session import SessionLocal -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def db() -> Generator: - yield SessionLocal() + db = None + try: + db = SessionLocal() + yield db + finally: + if db is not None: + db.close() @pytest.fixture(scope="module") From 182e2293a7d63ba9841fe9069d89041ce593f171 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Mon, 29 Nov 2021 13:11:45 +0100 Subject: [PATCH 02/22] Reworked models --- ensysmod/database/base_class.py | 3 +- ensysmod/database/base_class_timeseries.py | 21 +++++++++ ensysmod/model/__init__.py | 11 +++-- ensysmod/model/capacity.py | 12 ----- ensysmod/model/consumption.py | 13 ------ ensysmod/model/dataset.py | 16 +++++++ ensysmod/model/energy_commodity.py | 11 +++++ ensysmod/model/energy_component.py | 53 ++++++++++++++++++++++ ensysmod/model/energy_conversion.py | 13 ++++-- ensysmod/model/energy_conversion_factor.py | 15 ++++++ ensysmod/model/energy_sink.py | 11 +++-- ensysmod/model/energy_source.py | 12 +++-- ensysmod/model/energy_storage.py | 11 +++-- ensysmod/model/energy_transmission.py | 14 ++++++ ensysmod/model/generation.py | 12 ----- ensysmod/model/region.py | 10 +++- ensysmod/model/ts_capacity.py | 8 ++++ ensysmod/model/ts_consumption.py | 8 ++++ ensysmod/model/ts_generation.py | 8 ++++ tests/crud/test_energy_conversion.py | 2 + tests/database/test_tables.py | 32 +++++++++---- 21 files changed, 231 insertions(+), 65 deletions(-) create mode 100644 ensysmod/database/base_class_timeseries.py delete mode 100644 ensysmod/model/capacity.py delete mode 100644 ensysmod/model/consumption.py create mode 100644 ensysmod/model/dataset.py create mode 100644 ensysmod/model/energy_commodity.py create mode 100644 ensysmod/model/energy_component.py create mode 100644 ensysmod/model/energy_conversion_factor.py create mode 100644 ensysmod/model/energy_transmission.py delete mode 100644 ensysmod/model/generation.py create mode 100644 ensysmod/model/ts_capacity.py create mode 100644 ensysmod/model/ts_consumption.py create mode 100644 ensysmod/model/ts_generation.py diff --git a/ensysmod/database/base_class.py b/ensysmod/database/base_class.py index 3b8618e..bdb4150 100644 --- a/ensysmod/database/base_class.py +++ b/ensysmod/database/base_class.py @@ -1,3 +1,4 @@ +import re from typing import Any from sqlalchemy.orm import as_declarative, declared_attr @@ -14,4 +15,4 @@ class Base: # Generate __tablename__ automatically @declared_attr def __tablename__(self) -> str: - return self.__name__.lower() + return re.sub(r'(? Date: Mon, 29 Nov 2021 14:03:01 +0100 Subject: [PATCH 03/22] Renamed base_class_timeseries.py to ts_base_class.py --- .../database/{base_class_timeseries.py => ts_base_class.py} | 3 +++ ensysmod/model/ts_capacity.py | 2 +- ensysmod/model/ts_consumption.py | 2 +- ensysmod/model/ts_generation.py | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) rename ensysmod/database/{base_class_timeseries.py => ts_base_class.py} (91%) diff --git a/ensysmod/database/base_class_timeseries.py b/ensysmod/database/ts_base_class.py similarity index 91% rename from ensysmod/database/base_class_timeseries.py rename to ensysmod/database/ts_base_class.py index 3dfa1ed..ccf2462 100644 --- a/ensysmod/database/base_class_timeseries.py +++ b/ensysmod/database/ts_base_class.py @@ -4,6 +4,9 @@ class TimeSeriesBase: + """ + Base class for all time series classes. + """ @declared_attr def id(self): return Column(Integer, primary_key=True) diff --git a/ensysmod/model/ts_capacity.py b/ensysmod/model/ts_capacity.py index 2bbc3dd..1ffa2e3 100644 --- a/ensysmod/model/ts_capacity.py +++ b/ensysmod/model/ts_capacity.py @@ -1,7 +1,7 @@ from sqlalchemy import Column, DECIMAL from ensysmod.database.base_class import Base -from ensysmod.database.base_class_timeseries import TimeSeriesBase +from ensysmod.database.ts_base_class import TimeSeriesBase class Capacity(TimeSeriesBase, Base): diff --git a/ensysmod/model/ts_consumption.py b/ensysmod/model/ts_consumption.py index 411228a..9baf6f0 100644 --- a/ensysmod/model/ts_consumption.py +++ b/ensysmod/model/ts_consumption.py @@ -1,7 +1,7 @@ from sqlalchemy import Column, DECIMAL from ensysmod.database.base_class import Base -from ensysmod.database.base_class_timeseries import TimeSeriesBase +from ensysmod.database.ts_base_class import TimeSeriesBase class Consumption(TimeSeriesBase, Base): diff --git a/ensysmod/model/ts_generation.py b/ensysmod/model/ts_generation.py index 2b4fcf3..cf85ac3 100644 --- a/ensysmod/model/ts_generation.py +++ b/ensysmod/model/ts_generation.py @@ -1,7 +1,7 @@ from sqlalchemy import Column, DECIMAL from ensysmod.database.base_class import Base -from ensysmod.database.base_class_timeseries import TimeSeriesBase +from ensysmod.database.ts_base_class import TimeSeriesBase class Generation(TimeSeriesBase, Base): From 6db52b952447b908dafb833e660f65d40da694aa Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:32:08 +0100 Subject: [PATCH 04/22] Added unique constraint for component reference --- ensysmod/model/energy_conversion.py | 2 +- ensysmod/model/energy_sink.py | 2 +- ensysmod/model/energy_source.py | 2 +- ensysmod/model/energy_storage.py | 2 +- ensysmod/model/energy_transmission.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ensysmod/model/energy_conversion.py b/ensysmod/model/energy_conversion.py index 6a31095..3d299ac 100644 --- a/ensysmod/model/energy_conversion.py +++ b/ensysmod/model/energy_conversion.py @@ -12,5 +12,5 @@ class EnergyConversion(Base): See https://vsa-fine.readthedocs.io/en/latest/conversionClassDoc.html """ id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) commodity_unit = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) diff --git a/ensysmod/model/energy_sink.py b/ensysmod/model/energy_sink.py index b428a95..db3a084 100644 --- a/ensysmod/model/energy_sink.py +++ b/ensysmod/model/energy_sink.py @@ -10,5 +10,5 @@ class EnergySink(Base): See https://vsa-fine.readthedocs.io/en/latest/sourceSinkClassDoc.html """ id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) diff --git a/ensysmod/model/energy_source.py b/ensysmod/model/energy_source.py index 7b8c2a4..66ea90b 100644 --- a/ensysmod/model/energy_source.py +++ b/ensysmod/model/energy_source.py @@ -10,6 +10,6 @@ class EnergySource(Base): See https://vsa-fine.readthedocs.io/en/latest/sourceSinkClassDoc.html """ id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) diff --git a/ensysmod/model/energy_storage.py b/ensysmod/model/energy_storage.py index dcb85e1..b95dacc 100644 --- a/ensysmod/model/energy_storage.py +++ b/ensysmod/model/energy_storage.py @@ -10,5 +10,5 @@ class EnergyStorage(Base): See https://vsa-fine.readthedocs.io/en/latest/storageClassDoc.html """ id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) diff --git a/ensysmod/model/energy_transmission.py b/ensysmod/model/energy_transmission.py index 3d92f94..8bdf188 100644 --- a/ensysmod/model/energy_transmission.py +++ b/ensysmod/model/energy_transmission.py @@ -10,5 +10,5 @@ class EnergyTransmission(Base): See https://vsa-fine.readthedocs.io/en/latest/storageClassDoc.html """ id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) From 01647f55a1766e6a7133cde5dc1e7eededea6a9c Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Wed, 1 Dec 2021 23:08:29 +0100 Subject: [PATCH 05/22] Added relationships between models --- ensysmod/model/energy_commodity.py | 8 ++++++++ ensysmod/model/energy_component.py | 3 +-- ensysmod/model/energy_conversion.py | 10 +++++++--- ensysmod/model/energy_sink.py | 10 +++++++--- ensysmod/model/energy_source.py | 7 +++++-- ensysmod/model/energy_storage.py | 10 +++++++--- ensysmod/model/energy_transmission.py | 10 +++++++--- 7 files changed, 42 insertions(+), 16 deletions(-) diff --git a/ensysmod/model/energy_commodity.py b/ensysmod/model/energy_commodity.py index 1d000fb..ae16e2c 100644 --- a/ensysmod/model/energy_commodity.py +++ b/ensysmod/model/energy_commodity.py @@ -1,4 +1,5 @@ from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -9,3 +10,10 @@ class EnergyCommodity(Base): name = Column(String, unique=True, index=True, nullable=False) description = Column(String, nullable=True) unit = Column(String, nullable=False) + + # relationships + energy_conversions = relationship("EnergyConversion", back_populates="commodity") + energy_sources = relationship("EnergySource", back_populates="commodity") + energy_sinks = relationship("EnergySink", back_populates="commodity") + energy_storages = relationship("EnergyStorage", back_populates="commodity") + energy_transmissions = relationship("EnergyTransmission", back_populates="commodity") diff --git a/ensysmod/model/energy_component.py b/ensysmod/model/energy_component.py index 7f97fa9..0fd1bb7 100644 --- a/ensysmod/model/energy_component.py +++ b/ensysmod/model/energy_component.py @@ -1,6 +1,7 @@ import enum from sqlalchemy import Column, Integer, String, Boolean, DECIMAL, ForeignKey, Enum +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -48,6 +49,4 @@ class EnergyComponent(Base): interest_rate = Column(DECIMAL, nullable=False, default=0.08) economic_lifetime = Column(Integer, nullable=False, default=10) - # Relationships - # constraint capacityVariableDomain diff --git a/ensysmod/model/energy_conversion.py b/ensysmod/model/energy_conversion.py index 3d299ac..e4cff32 100644 --- a/ensysmod/model/energy_conversion.py +++ b/ensysmod/model/energy_conversion.py @@ -1,4 +1,5 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, ForeignKey +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -11,6 +12,9 @@ class EnergyConversion(Base): It is used to convert one commodity to another. See https://vsa-fine.readthedocs.io/en/latest/conversionClassDoc.html """ - id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) commodity_unit = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + + # Relationships + component = relationship("EnergyComponent") + commodity = relationship("EnergyCommodity", back_populates="energy_conversions") diff --git a/ensysmod/model/energy_sink.py b/ensysmod/model/energy_sink.py index db3a084..0180c1b 100644 --- a/ensysmod/model/energy_sink.py +++ b/ensysmod/model/energy_sink.py @@ -1,4 +1,5 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, ForeignKey +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -9,6 +10,9 @@ class EnergySink(Base): See https://vsa-fine.readthedocs.io/en/latest/sourceSinkClassDoc.html """ - id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + + # Relationships + component = relationship("EnergyComponent") + commodity = relationship("EnergyCommodity", back_populates="energy_sinks") diff --git a/ensysmod/model/energy_source.py b/ensysmod/model/energy_source.py index 66ea90b..323fefe 100644 --- a/ensysmod/model/energy_source.py +++ b/ensysmod/model/energy_source.py @@ -1,4 +1,5 @@ from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -9,7 +10,9 @@ class EnergySource(Base): See https://vsa-fine.readthedocs.io/en/latest/sourceSinkClassDoc.html """ - id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + # Relationships + component = relationship("EnergyComponent") + commodity = relationship("EnergyCommodity", back_populates="energy_sources") diff --git a/ensysmod/model/energy_storage.py b/ensysmod/model/energy_storage.py index b95dacc..4328883 100644 --- a/ensysmod/model/energy_storage.py +++ b/ensysmod/model/energy_storage.py @@ -1,4 +1,5 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, ForeignKey +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -9,6 +10,9 @@ class EnergyStorage(Base): See https://vsa-fine.readthedocs.io/en/latest/storageClassDoc.html """ - id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + + # Relationships + component = relationship("EnergyComponent") + commodity = relationship("EnergyCommodity", back_populates="energy_storages") diff --git a/ensysmod/model/energy_transmission.py b/ensysmod/model/energy_transmission.py index 8bdf188..3bbc9b3 100644 --- a/ensysmod/model/energy_transmission.py +++ b/ensysmod/model/energy_transmission.py @@ -1,4 +1,5 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, ForeignKey +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -9,6 +10,9 @@ class EnergyTransmission(Base): See https://vsa-fine.readthedocs.io/en/latest/storageClassDoc.html """ - id = Column(Integer, primary_key=True, index=True) - ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, unique=True) + ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + + # Relationships + component = relationship("EnergyComponent") + commodity = relationship("EnergyCommodity", back_populates="energy_transmissions") From e4f568093bb144a35e7afc20bb3431b51c21be6c Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 2 Dec 2021 00:02:32 +0100 Subject: [PATCH 06/22] Added api endpoints for multiple models Reworked models Added schemas Added crud operations Added endpoints Added default user for tests Added tests for endpoints Added prefix ts_ for all time series related models --- ensysmod/api/api.py | 10 ++- ensysmod/api/endpoints/datasets.py | 72 ++++++++++++++++ ensysmod/api/endpoints/energy_commodities.py | 82 ++++++++++++++++++ ensysmod/api/endpoints/energy_conversions.py | 50 +++++++++++ ensysmod/api/endpoints/energy_sinks.py | 49 +++++++++++ ensysmod/api/endpoints/energy_sources.py | 49 +++++++++++ ensysmod/api/endpoints/energy_storages.py | 49 +++++++++++ .../api/endpoints/energy_transmissions.py | 50 +++++++++++ ensysmod/app.py | 11 ++- ensysmod/crud/__init__.py | 10 ++- ensysmod/crud/base.py | 2 +- ensysmod/crud/dataset.py | 20 +++++ ensysmod/crud/energy_commodity.py | 29 +++++++ ensysmod/crud/energy_component.py | 22 +++++ ensysmod/crud/energy_conversion.py | 35 +++++++- ensysmod/crud/energy_sink.py | 32 ++++++- ensysmod/crud/energy_source.py | 32 ++++++- ensysmod/crud/energy_storage.py | 35 +++++++- ensysmod/crud/energy_transmission.py | 44 ++++++++++ ensysmod/crud/{capacity.py => ts_capacity.py} | 0 .../{consumption.py => ts_consumption.py} | 0 .../crud/{generation.py => ts_generation.py} | 0 ensysmod/crud/user.py | 15 +++- ensysmod/database/ts_base_class.py | 1 + ensysmod/model/__init__.py | 2 +- ensysmod/model/energy_commodity.py | 3 +- ensysmod/model/energy_component.py | 17 ++-- ensysmod/model/energy_conversion.py | 4 +- ensysmod/model/energy_conversion_factor.py | 2 +- ensysmod/model/energy_source.py | 2 +- ensysmod/model/energy_storage.py | 1 + ensysmod/model/energy_transmission.py | 1 + ensysmod/model/region.py | 1 - ensysmod/schemas/__init__.py | 18 ++-- ensysmod/schemas/dataset.py | 35 ++++++++ ensysmod/schemas/energy_commodity.py | 40 +++++++++ ensysmod/schemas/energy_component.py | 39 +++++++++ ensysmod/schemas/energy_conversion.py | 46 +++++----- ensysmod/schemas/energy_sink.py | 46 +++++----- ensysmod/schemas/energy_source.py | 46 +++++----- ensysmod/schemas/energy_storage.py | 46 +++++----- ensysmod/schemas/energy_transmission.py | 39 +++++++++ .../schemas/{capacity.py => ts_capacity.py} | 0 .../{consumption.py => ts_consumption.py} | 0 .../{generation.py => ts_generation.py} | 0 tests/api/test_datasets.py | 86 +++++++++++++++++++ tests/api/test_energy_commodities.py | 51 +++++++++++ tests/api/test_energy_conversions.py | 45 ++++++++++ tests/api/test_energy_sinks.py | 45 ++++++++++ tests/api/test_energy_sources.py | 45 ++++++++++ tests/api/test_energy_storages.py | 45 ++++++++++ tests/api/test_energy_transmissions.py | 45 ++++++++++ tests/conftest.py | 8 ++ tests/utils/utils.py | 47 ++++++++++ 54 files changed, 1380 insertions(+), 124 deletions(-) create mode 100644 ensysmod/api/endpoints/datasets.py create mode 100644 ensysmod/api/endpoints/energy_commodities.py create mode 100644 ensysmod/api/endpoints/energy_conversions.py create mode 100644 ensysmod/api/endpoints/energy_sinks.py create mode 100644 ensysmod/api/endpoints/energy_sources.py create mode 100644 ensysmod/api/endpoints/energy_storages.py create mode 100644 ensysmod/api/endpoints/energy_transmissions.py create mode 100644 ensysmod/crud/dataset.py create mode 100644 ensysmod/crud/energy_commodity.py create mode 100644 ensysmod/crud/energy_component.py create mode 100644 ensysmod/crud/energy_transmission.py rename ensysmod/crud/{capacity.py => ts_capacity.py} (100%) rename ensysmod/crud/{consumption.py => ts_consumption.py} (100%) rename ensysmod/crud/{generation.py => ts_generation.py} (100%) create mode 100644 ensysmod/schemas/dataset.py create mode 100644 ensysmod/schemas/energy_commodity.py create mode 100644 ensysmod/schemas/energy_component.py create mode 100644 ensysmod/schemas/energy_transmission.py rename ensysmod/schemas/{capacity.py => ts_capacity.py} (100%) rename ensysmod/schemas/{consumption.py => ts_consumption.py} (100%) rename ensysmod/schemas/{generation.py => ts_generation.py} (100%) create mode 100644 tests/api/test_datasets.py create mode 100644 tests/api/test_energy_commodities.py create mode 100644 tests/api/test_energy_conversions.py create mode 100644 tests/api/test_energy_sinks.py create mode 100644 tests/api/test_energy_sources.py create mode 100644 tests/api/test_energy_storages.py create mode 100644 tests/api/test_energy_transmissions.py diff --git a/ensysmod/api/api.py b/ensysmod/api/api.py index 86e63f0..a0625a9 100644 --- a/ensysmod/api/api.py +++ b/ensysmod/api/api.py @@ -1,7 +1,15 @@ from fastapi import APIRouter -from .endpoints import users, authentication +from .endpoints import users, authentication, energy_sources, datasets, energy_commodities, energy_sinks, \ + energy_storages, energy_transmissions, energy_conversions api_router = APIRouter() api_router.include_router(authentication.router, prefix="/auth", tags=["Authentication"]) api_router.include_router(users.router, prefix="/users", tags=["Users"]) +api_router.include_router(datasets.router, prefix="/datasets", tags=["Datasets"]) +api_router.include_router(energy_commodities.router, prefix="/commodities", tags=["Commodities"]) +api_router.include_router(energy_conversions.router, prefix="/conversions", tags=["Energy Conversions"]) +api_router.include_router(energy_sinks.router, prefix="/sinks", tags=["Energy Sinks"]) +api_router.include_router(energy_sources.router, prefix="/sources", tags=["Energy Sources"]) +api_router.include_router(energy_storages.router, prefix="/storages", tags=["Energy Storages"]) +api_router.include_router(energy_transmissions.router, prefix="/transmissions", tags=["Energy Transmissions"]) diff --git a/ensysmod/api/endpoints/datasets.py b/ensysmod/api/endpoints/datasets.py new file mode 100644 index 0000000..bba9823 --- /dev/null +++ b/ensysmod/api/endpoints/datasets.py @@ -0,0 +1,72 @@ +from typing import List + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.Dataset]) +def all_datasets(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.Dataset]: + """ + Retrieve all datasets. + """ + return crud.dataset.get_multi(db=db, skip=skip, limit=limit) + + +@router.get("/{dataset_id}", response_model=schemas.Dataset) +def get_dataset(dataset_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Retrieve a dataset. + """ + # TODO Check if user has permission for dataset + return crud.dataset.get(db, dataset_id) + + +@router.post("/", response_model=schemas.Dataset) +def create_dataset(request: schemas.DatasetCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new dataset. + """ + # TODO Check if user has permission for dataset + existing_ds = crud.dataset.get_by_name(db=db, name=request.name) + if existing_ds is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=f"Dataset {request.name} already exists!") + + return crud.dataset.create(db=db, obj_in=request) + + +@router.put("/{dataset_id}", response_model=schemas.Dataset) +def update_dataset(dataset_id: int, + request: schemas.DatasetUpdate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Update a dataset. + """ + # TODO Check if user has permission for dataset + dataset = crud.dataset.get(db=db, id=dataset_id) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {dataset_id} not found!") + return crud.dataset.update(db=db, db_obj=dataset, obj_in=request) + + +@router.delete("/{dataset_id}", response_model=schemas.Dataset) +def remove_dataset(dataset_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Delete a dataset. + """ + # TODO Check if user has permission for dataset + return crud.dataset.remove(db=db, id=dataset_id) diff --git a/ensysmod/api/endpoints/energy_commodities.py b/ensysmod/api/endpoints/energy_commodities.py new file mode 100644 index 0000000..fc43712 --- /dev/null +++ b/ensysmod/api/endpoints/energy_commodities.py @@ -0,0 +1,82 @@ +from typing import List, Union + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.EnergyCommodity]) +def all_commodities(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100, + dataset: Union[None, int] = None) -> List[schemas.EnergyCommodity]: + """ + Retrieve all energy commodities. + """ + if dataset is None: + return crud.energy_commodity.get_multi(db, skip=skip, limit=limit) + else: + return crud.energy_commodity.get_multi_by_dataset(db, dataset_id=dataset, skip=skip, limit=limit) + + +@router.get("/{commodity_id}", response_model=schemas.EnergyCommodity) +def get_commodity(commodity_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Retrieve a energy commodity. + """ + # TODO Check if user has permission for dataset and commodity + return crud.energy_commodity.get(db, commodity_id) + + +@router.post("/", response_model=schemas.EnergyCommodity) +def create_commodity(request: schemas.EnergyCommodityCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new energy commodity. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"EnergyCommodity {request.name} already for dataset {request.ref_dataset} exists!") + + return crud.energy_commodity.create(db=db, obj_in=request) + + +@router.put("/{commodity_id}", response_model=schemas.EnergyCommodity) +def update_commodity(commodity_id: int, + request: schemas.EnergyCommodityUpdate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Update a energy commodity. + """ + # TODO Check if user has permission for commodity + commodity = crud.energy_commodity.get(db=db, id=commodity_id) + if commodity is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"EnergyCommodity {commodity_id} not found!") + return crud.energy_commodity.update(db=db, db_obj=commodity, obj_in=request) + + +@router.delete("/{commodity_id}", response_model=schemas.EnergyCommodity) +def remove_commodity(commodity_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Delete a energy commodity. + """ + # TODO Check if user has permission for dataset + return crud.energy_commodity.remove(db=db, id=commodity_id) diff --git a/ensysmod/api/endpoints/energy_conversions.py b/ensysmod/api/endpoints/energy_conversions.py new file mode 100644 index 0000000..cb62571 --- /dev/null +++ b/ensysmod/api/endpoints/energy_conversions.py @@ -0,0 +1,50 @@ +from typing import List + +from fastapi import APIRouter, Depends, HTTPException +from fastapi import status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.EnergyConversion]) +def all_energy_conversions(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.EnergyConversion]: + """ + Retrieve all energy conversions. + """ + return crud.energy_conversion.get_multi(db, skip, limit) + + +@router.post("/", response_model=schemas.EnergyConversion) +def create_conversion(request: schemas.EnergyConversionCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new energy conversion. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.energy_conversion.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"EnergyConversion {request.name} already for dataset {request.ref_dataset} exists!") + + # Check if energy commodity exists + commodity = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, + name=request.commodity_unit) + if commodity is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"EnergyCommodity {request.commodity_unit} " + f"in dataset {request.ref_dataset} not found!") + + return crud.energy_conversion.create(db=db, obj_in=request) diff --git a/ensysmod/api/endpoints/energy_sinks.py b/ensysmod/api/endpoints/energy_sinks.py new file mode 100644 index 0000000..95ad8bf --- /dev/null +++ b/ensysmod/api/endpoints/energy_sinks.py @@ -0,0 +1,49 @@ +from typing import List + +from fastapi import APIRouter, Depends, HTTPException +from fastapi import status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.EnergySink]) +def all_energy_sinks(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.EnergySink]: + """ + Retrieve all energy sinks. + """ + return crud.energy_sink.get_multi(db, skip, limit) + + +@router.post("/", response_model=schemas.EnergySink) +def create_sink(request: schemas.EnergySinkCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new energy sink. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.energy_sink.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"EnergySink {request.name} already for dataset {request.ref_dataset} exists!") + + # Check if energy commodity exists + commodity = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, + name=request.commodity) + if commodity is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"EnergyCommodity {request.commodity} in dataset {request.ref_dataset} not found!") + + return crud.energy_sink.create(db=db, obj_in=request) diff --git a/ensysmod/api/endpoints/energy_sources.py b/ensysmod/api/endpoints/energy_sources.py new file mode 100644 index 0000000..2fc5521 --- /dev/null +++ b/ensysmod/api/endpoints/energy_sources.py @@ -0,0 +1,49 @@ +from typing import List + +from fastapi import APIRouter, Depends, HTTPException +from fastapi import status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.EnergySource]) +def all_energy_sources(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.EnergySource]: + """ + Retrieve all energy sources. + """ + return crud.energy_source.get_multi(db, skip, limit) + + +@router.post("/", response_model=schemas.EnergySource) +def create_source(request: schemas.EnergySourceCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new energy source. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.energy_source.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"EnergySource {request.name} already for dataset {request.ref_dataset} exists!") + + # Check if energy commodity exists + commodity = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, + name=request.commodity) + if commodity is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"EnergyCommodity {request.commodity} in dataset {request.ref_dataset} not found!") + + return crud.energy_source.create(db=db, obj_in=request) diff --git a/ensysmod/api/endpoints/energy_storages.py b/ensysmod/api/endpoints/energy_storages.py new file mode 100644 index 0000000..be786f7 --- /dev/null +++ b/ensysmod/api/endpoints/energy_storages.py @@ -0,0 +1,49 @@ +from typing import List + +from fastapi import APIRouter, Depends, HTTPException +from fastapi import status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.EnergyStorage]) +def all_energy_storages(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.EnergyStorage]: + """ + Retrieve all energy storages. + """ + return crud.energy_storage.get_multi(db, skip, limit) + + +@router.post("/", response_model=schemas.EnergyStorage) +def create_storage(request: schemas.EnergyStorageCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new energy storage. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.energy_storage.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"EnergyStorage {request.name} already for dataset {request.ref_dataset} exists!") + + # Check if energy commodity exists + commodity = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, + name=request.commodity) + if commodity is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"EnergyCommodity {request.commodity} in dataset {request.ref_dataset} not found!") + + return crud.energy_storage.create(db=db, obj_in=request) diff --git a/ensysmod/api/endpoints/energy_transmissions.py b/ensysmod/api/endpoints/energy_transmissions.py new file mode 100644 index 0000000..101471b --- /dev/null +++ b/ensysmod/api/endpoints/energy_transmissions.py @@ -0,0 +1,50 @@ +from typing import List + +from fastapi import APIRouter, Depends, HTTPException +from fastapi import status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.EnergyTransmission]) +def all_energy_transmissions(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.EnergyTransmission]: + """ + Retrieve all energy transmissions. + """ + return crud.energy_transmission.get_multi(db, skip, limit) + + +@router.post("/", response_model=schemas.EnergyTransmission) +def create_transmission(request: schemas.EnergyTransmissionCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new energy transmission. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.energy_transmission.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, + name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"EnergyTransmission {request.name} already for dataset {request.ref_dataset} exists!") + + # Check if energy commodity exists + commodity = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, + name=request.commodity) + if commodity is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"EnergyCommodity {request.commodity} in dataset {request.ref_dataset} not found!") + + return crud.energy_transmission.create(db=db, obj_in=request) diff --git a/ensysmod/app.py b/ensysmod/app.py index 6983f68..754492a 100644 --- a/ensysmod/app.py +++ b/ensysmod/app.py @@ -1,4 +1,5 @@ -from fastapi import FastAPI +from fastapi import FastAPI, status, Request +from fastapi.responses import JSONResponse from ensysmod.api import api_router from ensysmod.core import settings @@ -14,3 +15,11 @@ def init_database(): init_db.check_connection() init_db.create_all() + + +@app.exception_handler(Exception) +async def exception_handler(request: Request, exc: Exception): + return JSONResponse( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + content={"detail": str(exc)}, + ) diff --git a/ensysmod/crud/__init__.py b/ensysmod/crud/__init__.py index 0d11080..6367599 100644 --- a/ensysmod/crud/__init__.py +++ b/ensysmod/crud/__init__.py @@ -1,12 +1,16 @@ """ This package contains the CRUD operations (CREATE, READ, UPDATE, DELETE) for each repository/table in database. """ -from .capacity import capacity -from .consumption import consumption +from .dataset import dataset +from .energy_commodity import energy_commodity +from .energy_component import energy_component from .energy_conversion import energy_conversion from .energy_sink import energy_sink from .energy_source import energy_source from .energy_storage import energy_storage -from .generation import generation +from .energy_transmission import energy_transmission from .region import region +from .ts_capacity import capacity +from .ts_consumption import consumption +from .ts_generation import generation from .user import user diff --git a/ensysmod/crud/base.py b/ensysmod/crud/base.py index 861ae01..a677711 100644 --- a/ensysmod/crud/base.py +++ b/ensysmod/crud/base.py @@ -30,7 +30,7 @@ def get_multi( return db.query(self.model).offset(skip).limit(limit).all() def create(self, db: Session, *, obj_in: CreateSchemaType) -> ModelType: - obj_in_data = jsonable_encoder(obj_in) + obj_in_data = jsonable_encoder(obj_in, include=self.model.__table__.columns.keys()) db_obj = self.model(**obj_in_data) # type: ignore db.add(db_obj) db.commit() diff --git a/ensysmod/crud/dataset.py b/ensysmod/crud/dataset.py new file mode 100644 index 0000000..8fdf9fb --- /dev/null +++ b/ensysmod/crud/dataset.py @@ -0,0 +1,20 @@ +from typing import Optional + +from sqlalchemy.orm import Session + +from ensysmod.crud.base import CRUDBase +from ensysmod.model import Dataset +from ensysmod.schemas import DatasetCreate, DatasetUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDDataset(CRUDBase[Dataset, DatasetCreate, DatasetUpdate]): + """ + CRUD operations for Dataset + """ + + def get_by_name(self, db: Session, *, name: str) -> Optional[Dataset]: + return db.query(Dataset).filter(Dataset.name == name).first() + + +dataset = CRUDDataset(Dataset) diff --git a/ensysmod/crud/energy_commodity.py b/ensysmod/crud/energy_commodity.py new file mode 100644 index 0000000..10350b2 --- /dev/null +++ b/ensysmod/crud/energy_commodity.py @@ -0,0 +1,29 @@ +from typing import Optional, List + +from sqlalchemy.orm import Session + +from ensysmod.crud.base import CRUDBase +from ensysmod.model import EnergyCommodity +from ensysmod.schemas import EnergyCommodityCreate, EnergyCommodityUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDEnergyCommodity(CRUDBase[EnergyCommodity, EnergyCommodityCreate, EnergyCommodityUpdate]): + """ + CRUD operations for EnergyCommodity + """ + + def get_multi_by_dataset( + self, db: Session, *, skip: int = 0, limit: int = 100, dataset_id: int + ) -> List[EnergyCommodity]: + return db.query(EnergyCommodity) \ + .filter(EnergyCommodity.ref_dataset == dataset_id) \ + .offset(skip).limit(limit).all() + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergyCommodity]: + return db.query(EnergyCommodity) \ + .filter(EnergyCommodity.name == name and EnergyCommodity.ref_dataset == dataset_id) \ + .first() + + +energy_commodity = CRUDEnergyCommodity(EnergyCommodity) diff --git a/ensysmod/crud/energy_component.py b/ensysmod/crud/energy_component.py new file mode 100644 index 0000000..d4b312e --- /dev/null +++ b/ensysmod/crud/energy_component.py @@ -0,0 +1,22 @@ +from typing import Optional + +from sqlalchemy.orm import Session + +from ensysmod.crud.base import CRUDBase +from ensysmod.model import EnergyComponent +from ensysmod.schemas import EnergyComponentCreate, EnergyComponentUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDEnergyComponent(CRUDBase[EnergyComponent, EnergyComponentCreate, EnergyComponentUpdate]): + """ + CRUD operations for EnergyComponent + """ + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergyComponent]: + return db.query(EnergyComponent) \ + .filter(EnergyComponent.name == name and EnergyComponent.ref_dataset == dataset_id) \ + .first() + + +energy_component = CRUDEnergyComponent(EnergyComponent) diff --git a/ensysmod/crud/energy_conversion.py b/ensysmod/crud/energy_conversion.py index 12575e8..972dd10 100644 --- a/ensysmod/crud/energy_conversion.py +++ b/ensysmod/crud/energy_conversion.py @@ -1,3 +1,8 @@ +from typing import Optional + +from sqlalchemy.orm import Session + +from ensysmod import crud from ensysmod.crud.base import CRUDBase from ensysmod.model import EnergyConversion from ensysmod.schemas import EnergyConversionCreate, EnergyConversionUpdate @@ -5,7 +10,35 @@ # noinspection PyMethodMayBeStatic,PyArgumentList class CRUDEnergyConversion(CRUDBase[EnergyConversion, EnergyConversionCreate, EnergyConversionUpdate]): - pass + """ + CRUD operations for EnergyConversion + """ + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergyConversion]: + component = crud.energy_component.get_by_dataset_and_name(db, dataset_id=dataset_id, name=name) + if component is None: + return None + return db.query(EnergyConversion).filter(EnergyConversion.ref_component == component.id).first() + + def create(self, db: Session, *, obj_in: EnergyConversionCreate) -> EnergyConversion: + component = crud.energy_component.create(db, obj_in=obj_in) + commodity = crud.energy_commodity.get_by_dataset_and_name(db, name=obj_in.commodity_unit, + dataset_id=obj_in.ref_dataset) + db_obj = EnergyConversion( + ref_component=component.id, + ref_commodity_unit=commodity.id, + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + def remove(self, db: Session, *, id: int) -> EnergyConversion: + db_obj = super().remove(db=db, id=id) + crud.energy_component.remove(db, id=id) + return db_obj + + # TODO update energy conversion energy_conversion = CRUDEnergyConversion(EnergyConversion) diff --git a/ensysmod/crud/energy_sink.py b/ensysmod/crud/energy_sink.py index 0835daf..0eb9676 100644 --- a/ensysmod/crud/energy_sink.py +++ b/ensysmod/crud/energy_sink.py @@ -2,6 +2,7 @@ from sqlalchemy.orm import Session +from ensysmod import crud from ensysmod.crud.base import CRUDBase from ensysmod.model import EnergySink from ensysmod.schemas import EnergySinkCreate, EnergySinkUpdate @@ -9,8 +10,35 @@ # noinspection PyMethodMayBeStatic,PyArgumentList class CRUDEnergySink(CRUDBase[EnergySink, EnergySinkCreate, EnergySinkUpdate]): - def get_by_name(self, db: Session, *, name: str) -> Optional[EnergySink]: - return db.query(EnergySink).filter(EnergySink.name == name).first() + """ + CRUD operations for EnergySink + """ + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergySink]: + component = crud.energy_component.get_by_dataset_and_name(db, dataset_id=dataset_id, name=name) + if component is None: + return None + return db.query(EnergySink).filter(EnergySink.ref_component == component.id).first() + + def create(self, db: Session, *, obj_in: EnergySinkCreate) -> EnergySink: + component = crud.energy_component.create(db, obj_in=obj_in) + commodity = crud.energy_commodity.get_by_dataset_and_name(db, name=obj_in.commodity, + dataset_id=obj_in.ref_dataset) + db_obj = EnergySink( + ref_component=component.id, + ref_commodity=commodity.id, + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + def remove(self, db: Session, *, id: int) -> EnergySink: + db_obj = super().remove(db=db, id=id) + crud.energy_component.remove(db, id=id) + return db_obj + + # TODO update energy source energy_sink = CRUDEnergySink(EnergySink) diff --git a/ensysmod/crud/energy_source.py b/ensysmod/crud/energy_source.py index eb425ae..be9fe0a 100644 --- a/ensysmod/crud/energy_source.py +++ b/ensysmod/crud/energy_source.py @@ -2,6 +2,7 @@ from sqlalchemy.orm import Session +from ensysmod import crud from ensysmod.crud.base import CRUDBase from ensysmod.model import EnergySource from ensysmod.schemas import EnergySourceCreate, EnergySourceUpdate @@ -9,8 +10,35 @@ # noinspection PyMethodMayBeStatic,PyArgumentList class CRUDEnergySource(CRUDBase[EnergySource, EnergySourceCreate, EnergySourceUpdate]): - def get_by_name(self, db: Session, *, name: str) -> Optional[EnergySource]: - return db.query(EnergySource).filter(EnergySource.name == name).first() + """ + CRUD operations for EnergySource + """ + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergySource]: + component = crud.energy_component.get_by_dataset_and_name(db, dataset_id=dataset_id, name=name) + if component is None: + return None + return db.query(EnergySource).filter(EnergySource.ref_component == component.id).first() + + def create(self, db: Session, *, obj_in: EnergySourceCreate) -> EnergySource: + component = crud.energy_component.create(db, obj_in=obj_in) + commodity = crud.energy_commodity.get_by_dataset_and_name(db, name=obj_in.commodity, + dataset_id=obj_in.ref_dataset) + db_obj = EnergySource( + ref_component=component.id, + ref_commodity=commodity.id, + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + def remove(self, db: Session, *, id: int) -> EnergySource: + db_obj = super().remove(db=db, id=id) + crud.energy_component.remove(db, id=id) + return db_obj + + # TODO update energy source energy_source = CRUDEnergySource(EnergySource) diff --git a/ensysmod/crud/energy_storage.py b/ensysmod/crud/energy_storage.py index e689e7d..314c334 100644 --- a/ensysmod/crud/energy_storage.py +++ b/ensysmod/crud/energy_storage.py @@ -1,3 +1,8 @@ +from typing import Optional + +from sqlalchemy.orm import Session + +from ensysmod import crud from ensysmod.crud.base import CRUDBase from ensysmod.model import EnergyStorage from ensysmod.schemas import EnergyStorageCreate, EnergyStorageUpdate @@ -5,7 +10,35 @@ # noinspection PyMethodMayBeStatic,PyArgumentList class CRUDEnergyStorage(CRUDBase[EnergyStorage, EnergyStorageCreate, EnergyStorageUpdate]): - pass + """ + CRUD operations for EnergyStorage + """ + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergyStorage]: + component = crud.energy_component.get_by_dataset_and_name(db, dataset_id=dataset_id, name=name) + if component is None: + return None + return db.query(EnergyStorage).filter(EnergyStorage.ref_component == component.id).first() + + def create(self, db: Session, *, obj_in: EnergyStorageCreate) -> EnergyStorage: + component = crud.energy_component.create(db, obj_in=obj_in) + commodity = crud.energy_commodity.get_by_dataset_and_name(db, name=obj_in.commodity, + dataset_id=obj_in.ref_dataset) + db_obj = EnergyStorage( + ref_component=component.id, + ref_commodity=commodity.id, + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + def remove(self, db: Session, *, id: int) -> EnergyStorage: + db_obj = super().remove(db=db, id=id) + crud.energy_component.remove(db, id=id) + return db_obj + + # TODO update energy storage energy_storage = CRUDEnergyStorage(EnergyStorage) diff --git a/ensysmod/crud/energy_transmission.py b/ensysmod/crud/energy_transmission.py new file mode 100644 index 0000000..9ec66b2 --- /dev/null +++ b/ensysmod/crud/energy_transmission.py @@ -0,0 +1,44 @@ +from typing import Optional + +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.crud.base import CRUDBase +from ensysmod.model import EnergyTransmission +from ensysmod.schemas import EnergyTransmissionCreate, EnergyTransmissionUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDEnergyTransmission(CRUDBase[EnergyTransmission, EnergyTransmissionCreate, EnergyTransmissionUpdate]): + """ + CRUD operations for EnergyTransmission + """ + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[EnergyTransmission]: + component = crud.energy_component.get_by_dataset_and_name(db, dataset_id=dataset_id, name=name) + if component is None: + return None + return db.query(EnergyTransmission).filter(EnergyTransmission.ref_component == component.id).first() + + def create(self, db: Session, *, obj_in: EnergyTransmissionCreate) -> EnergyTransmission: + component = crud.energy_component.create(db, obj_in=obj_in) + commodity = crud.energy_commodity.get_by_dataset_and_name(db, name=obj_in.commodity, + dataset_id=obj_in.ref_dataset) + db_obj = EnergyTransmission( + ref_component=component.id, + ref_commodity=commodity.id, + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + + def remove(self, db: Session, *, id: int) -> EnergyTransmission: + db_obj = super().remove(db=db, id=id) + crud.energy_component.remove(db, id=id) + return db_obj + + # TODO update energy transmission + + +energy_transmission = CRUDEnergyTransmission(EnergyTransmission) diff --git a/ensysmod/crud/capacity.py b/ensysmod/crud/ts_capacity.py similarity index 100% rename from ensysmod/crud/capacity.py rename to ensysmod/crud/ts_capacity.py diff --git a/ensysmod/crud/consumption.py b/ensysmod/crud/ts_consumption.py similarity index 100% rename from ensysmod/crud/consumption.py rename to ensysmod/crud/ts_consumption.py diff --git a/ensysmod/crud/generation.py b/ensysmod/crud/ts_generation.py similarity index 100% rename from ensysmod/crud/generation.py rename to ensysmod/crud/ts_generation.py diff --git a/ensysmod/crud/user.py b/ensysmod/crud/user.py index 8e910a4..925562d 100644 --- a/ensysmod/crud/user.py +++ b/ensysmod/crud/user.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Union, Dict, Any from sqlalchemy.orm import Session @@ -23,6 +23,19 @@ def create(self, db: Session, *, obj_in: UserCreate) -> User: db.refresh(db_obj) return db_obj + def update( + self, db: Session, *, db_obj: User, obj_in: Union[UserUpdate, Dict[str, Any]] + ) -> User: + if isinstance(obj_in, dict): + update_data = obj_in + else: + update_data = obj_in.dict(exclude_unset=True) + if update_data["password"]: + hashed_password = security.get_password_hash(update_data["password"]) + del update_data["password"] + update_data["hashed_password"] = hashed_password + return super().update(db, db_obj=db_obj, obj_in=update_data) + def authenticate(self, db: Session, *, username: str, password: str): user_obj = self.get_by_username(db, username=username) if not user_obj: diff --git a/ensysmod/database/ts_base_class.py b/ensysmod/database/ts_base_class.py index ccf2462..a60db1f 100644 --- a/ensysmod/database/ts_base_class.py +++ b/ensysmod/database/ts_base_class.py @@ -7,6 +7,7 @@ class TimeSeriesBase: """ Base class for all time series classes. """ + @declared_attr def id(self): return Column(Integer, primary_key=True) diff --git a/ensysmod/model/__init__.py b/ensysmod/model/__init__.py index ccffcee..02cef04 100644 --- a/ensysmod/model/__init__.py +++ b/ensysmod/model/__init__.py @@ -2,8 +2,8 @@ This package contains all models in database """ from .dataset import Dataset -from .energy_component import EnergyComponent, EnergyComponentType, CapacityVariableDomain from .energy_commodity import EnergyCommodity +from .energy_component import EnergyComponent, EnergyComponentType, CapacityVariableDomain from .energy_conversion import EnergyConversion from .energy_conversion_factor import EnergyConversionFactor from .energy_sink import EnergySink diff --git a/ensysmod/model/energy_commodity.py b/ensysmod/model/energy_commodity.py index ae16e2c..d05eaa3 100644 --- a/ensysmod/model/energy_commodity.py +++ b/ensysmod/model/energy_commodity.py @@ -12,7 +12,8 @@ class EnergyCommodity(Base): unit = Column(String, nullable=False) # relationships - energy_conversions = relationship("EnergyConversion", back_populates="commodity") + dataset = relationship("Dataset") + energy_conversions = relationship("EnergyConversion", back_populates="commodity_unit") energy_sources = relationship("EnergySource", back_populates="commodity") energy_sinks = relationship("EnergySink", back_populates="commodity") energy_storages = relationship("EnergyStorage", back_populates="commodity") diff --git a/ensysmod/model/energy_component.py b/ensysmod/model/energy_component.py index 0fd1bb7..ba1d52e 100644 --- a/ensysmod/model/energy_component.py +++ b/ensysmod/model/energy_component.py @@ -1,7 +1,6 @@ import enum from sqlalchemy import Column, Integer, String, Boolean, DECIMAL, ForeignKey, Enum -from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -10,19 +9,19 @@ class EnergyComponentType(enum.Enum): """ Enum for the different types of energy components. """ - SOURCE = 'source' - SINK = 'sink' - CONVERSION = 'conversion' - TRANSMISSION = 'transmission' - STORAGE = 'storage' + SOURCE = 'SOURCE' + SINK = 'SINK' + CONVERSION = 'CONVERSION' + TRANSMISSION = 'TRANSMISSION' + STORAGE = 'STORAGE' class CapacityVariableDomain(enum.Enum): """ Enum for the different types of capacity variables. """ - CONTINUOUS = 'continuous' - DISCRETE = 'discrete' + CONTINUOUS = 'CONTINUOUS' + DISCRETE = 'DISCRETE' class EnergyComponent(Base): @@ -38,7 +37,7 @@ class EnergyComponent(Base): description = Column(String, nullable=True) # specifies if the component should be modeled with a capacity or not. - capacity_variable = Column(Boolean, nullable=False) + capacity_variable = Column(Boolean, nullable=False, default=False) capacity_variable_domain = Column(Enum(CapacityVariableDomain), default=CapacityVariableDomain.CONTINUOUS, nullable=False) diff --git a/ensysmod/model/energy_conversion.py b/ensysmod/model/energy_conversion.py index e4cff32..fa570f3 100644 --- a/ensysmod/model/energy_conversion.py +++ b/ensysmod/model/energy_conversion.py @@ -13,8 +13,8 @@ class EnergyConversion(Base): See https://vsa-fine.readthedocs.io/en/latest/conversionClassDoc.html """ ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) - commodity_unit = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + ref_commodity_unit = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) # Relationships component = relationship("EnergyComponent") - commodity = relationship("EnergyCommodity", back_populates="energy_conversions") + commodity_unit = relationship("EnergyCommodity", back_populates="energy_conversions") diff --git a/ensysmod/model/energy_conversion_factor.py b/ensysmod/model/energy_conversion_factor.py index ce59096..bbeb1f2 100644 --- a/ensysmod/model/energy_conversion_factor.py +++ b/ensysmod/model/energy_conversion_factor.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, String, ForeignKey, DECIMAL +from sqlalchemy import Column, Integer, ForeignKey, DECIMAL from ensysmod.database.base_class import Base diff --git a/ensysmod/model/energy_source.py b/ensysmod/model/energy_source.py index 323fefe..19b36e7 100644 --- a/ensysmod/model/energy_source.py +++ b/ensysmod/model/energy_source.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base diff --git a/ensysmod/model/energy_storage.py b/ensysmod/model/energy_storage.py index 4328883..433bce0 100644 --- a/ensysmod/model/energy_storage.py +++ b/ensysmod/model/energy_storage.py @@ -12,6 +12,7 @@ class EnergyStorage(Base): """ ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + # TODO: add more fields # Relationships component = relationship("EnergyComponent") diff --git a/ensysmod/model/energy_transmission.py b/ensysmod/model/energy_transmission.py index 3bbc9b3..5585e8a 100644 --- a/ensysmod/model/energy_transmission.py +++ b/ensysmod/model/energy_transmission.py @@ -12,6 +12,7 @@ class EnergyTransmission(Base): """ ref_component = Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False, primary_key=True) ref_commodity = Column(Integer, ForeignKey("energy_commodity.id"), index=True, nullable=False) + # TODO: add more fields # Relationships component = relationship("EnergyComponent") diff --git a/ensysmod/model/region.py b/ensysmod/model/region.py index f9c395c..c3874e3 100644 --- a/ensysmod/model/region.py +++ b/ensysmod/model/region.py @@ -12,4 +12,3 @@ class Region(Base): id = Column(Integer, primary_key=True, index=True) ref_dataset = Column(Integer, ForeignKey("dataset.id"), index=True, nullable=False) name = Column(String, unique=True, index=True, nullable=False) - diff --git a/ensysmod/schemas/__init__.py b/ensysmod/schemas/__init__.py index 474634c..e1731e8 100644 --- a/ensysmod/schemas/__init__.py +++ b/ensysmod/schemas/__init__.py @@ -1,13 +1,17 @@ """ This package contains every model that is returned from the Rest-API. """ -from .capacity import Capacity, CapacityCreate, CapacityUpdate, CapacityInDB -from .consumption import Consumption, ConsumptionCreate, ConsumptionUpdate, ConsumptionInDB -from .energy_conversion import EnergyConversion, EnergyConversionCreate, EnergyConversionUpdate, EnergyConversionInDB -from .energy_sink import EnergySink, EnergySinkCreate, EnergySinkUpdate, EnergySinkInDB -from .energy_source import EnergySource, EnergySourceCreate, EnergySourceUpdate, EnergySourceInDB -from .energy_storage import EnergyStorage, EnergyStorageCreate, EnergyStorageUpdate, EnergyStorageInDB -from .generation import Generation, GenerationCreate, GenerationUpdate, GenerationInDB +from .dataset import Dataset, DatasetCreate, DatasetUpdate +from .energy_commodity import EnergyCommodity, EnergyCommodityCreate, EnergyCommodityUpdate +from .energy_component import EnergyComponent, EnergyComponentCreate, EnergyComponentUpdate +from .energy_conversion import EnergyConversion, EnergyConversionCreate, EnergyConversionUpdate +from .energy_sink import EnergySink, EnergySinkCreate, EnergySinkUpdate +from .energy_source import EnergySource, EnergySourceCreate, EnergySourceUpdate +from .energy_storage import EnergyStorage, EnergyStorageCreate, EnergyStorageUpdate +from .energy_transmission import EnergyTransmission, EnergyTransmissionCreate, EnergyTransmissionUpdate from .region import Region, RegionCreate, RegionUpdate, RegionInDB from .token import Token, TokenPayload +from .ts_capacity import Capacity, CapacityCreate, CapacityUpdate, CapacityInDB +from .ts_consumption import Consumption, ConsumptionCreate, ConsumptionUpdate, ConsumptionInDB +from .ts_generation import Generation, GenerationCreate, GenerationUpdate, GenerationInDB from .user import User, UserCreate, UserInDB, UserUpdate diff --git a/ensysmod/schemas/dataset.py b/ensysmod/schemas/dataset.py new file mode 100644 index 0000000..f7ba8c0 --- /dev/null +++ b/ensysmod/schemas/dataset.py @@ -0,0 +1,35 @@ +from typing import Optional + +from pydantic import BaseModel + + +class DatasetBase(BaseModel): + """ + Shared properties for a dataset. Used as a base class for all schemas. + """ + name: str + description: Optional[str] = None + + +class DatasetCreate(DatasetBase): + """ + Properties to receive via API on creation of a dataset. + """ + pass + + +class DatasetUpdate(DatasetBase): + """ + Properties to receive via API on update of a dataset. + """ + name: Optional[str] = None + + +class Dataset(DatasetBase): + """ + Properties to return via API for a dataset. + """ + id: int + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/energy_commodity.py b/ensysmod/schemas/energy_commodity.py new file mode 100644 index 0000000..9b74cf7 --- /dev/null +++ b/ensysmod/schemas/energy_commodity.py @@ -0,0 +1,40 @@ +from typing import Optional + +from pydantic import BaseModel + +from ensysmod.schemas import Dataset + + +class EnergyCommodityBase(BaseModel): + """ + Shared properties for an energy commodity. Used as a base class for all schemas. + """ + name: str + unit: str + description: Optional[str] = None + + +class EnergyCommodityCreate(EnergyCommodityBase): + """ + Properties to receive via API on creation of an energy commodity. + """ + ref_dataset: int + + +class EnergyCommodityUpdate(EnergyCommodityBase): + """ + Properties to receive via API on update of an energy commodity. + """ + name: Optional[str] = None + unit: Optional[str] = None + + +class EnergyCommodity(EnergyCommodityBase): + """ + Properties to return via API for an energy commodity. + """ + id: int + dataset: Dataset + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/energy_component.py b/ensysmod/schemas/energy_component.py new file mode 100644 index 0000000..23d9180 --- /dev/null +++ b/ensysmod/schemas/energy_component.py @@ -0,0 +1,39 @@ +from typing import Optional + +from pydantic import BaseModel + +from ensysmod.model import EnergyComponentType + + +class EnergyComponentBase(BaseModel): + """ + Shared properties for an energy component. Used as a base class for all schemas. + """ + name: str + type: EnergyComponentType + description: Optional[str] = None + + +class EnergyComponentCreate(EnergyComponentBase): + """ + Properties to receive via API on creation of an energy component. + """ + ref_dataset: int + + +class EnergyComponentUpdate(EnergyComponentBase): + """ + Properties to receive via API on update of an energy component. + """ + pass + + +# Additional properties to return via API +class EnergyComponent(EnergyComponentBase): + """ + Properties to return via API for an energy component. + """ + id: int + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/energy_conversion.py b/ensysmod/schemas/energy_conversion.py index 2456bb2..214323c 100644 --- a/ensysmod/schemas/energy_conversion.py +++ b/ensysmod/schemas/energy_conversion.py @@ -2,36 +2,38 @@ from pydantic import BaseModel +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyComponentCreate, EnergyComponent, EnergyComponentUpdate, EnergyCommodity + -# Shared properties class EnergyConversionBase(BaseModel): - name: Optional[str] = None + """ + Shared properties for an energy conversion. Used as a base class for all schemas. + """ + commodity_unit: str + type = EnergyComponentType.CONVERSION -# Properties to receive via API on creation -class EnergyConversionCreate(EnergyConversionBase): - name: str - description: Optional[str] = None +class EnergyConversionCreate(EnergyConversionBase, EnergyComponentCreate): + """ + Properties to receive via API on creation of an energy conversion. + """ + pass -# Properties to receive via API on update -class EnergyConversionUpdate(EnergyConversionBase): - name: Optional[str] = None - description: Optional[str] = None +class EnergyConversionUpdate(EnergyConversionBase, EnergyComponentUpdate): + """ + Properties to receive via API on update of an energy conversion. + """ + commodity_unit: Optional[str] = None -class EnergyConversionInDBBase(EnergyConversionBase): - id: Optional[int] = None +class EnergyConversion(EnergyConversionBase): + """ + Properties to return via API for an energy conversion. + """ + component: EnergyComponent + commodity_unit: EnergyCommodity class Config: orm_mode = True - - -# Additional properties to return via API -class EnergyConversion(EnergyConversionInDBBase): - pass - - -# Additional properties stored in DB -class EnergyConversionInDB(EnergyConversionInDBBase): - description: Optional[str] = None diff --git a/ensysmod/schemas/energy_sink.py b/ensysmod/schemas/energy_sink.py index ddafe5b..703b264 100644 --- a/ensysmod/schemas/energy_sink.py +++ b/ensysmod/schemas/energy_sink.py @@ -2,36 +2,38 @@ from pydantic import BaseModel +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyComponentCreate, EnergyComponentUpdate, EnergyComponent, EnergyCommodity + -# Shared properties class EnergySinkBase(BaseModel): - name: Optional[str] = None + """ + Shared properties for an energy sink. Used as a base class for all schemas. + """ + commodity: str + type = EnergyComponentType.SINK -# Properties to receive via API on creation -class EnergySinkCreate(EnergySinkBase): - name: str - description: Optional[str] = None +class EnergySinkCreate(EnergySinkBase, EnergyComponentCreate): + """ + Properties to receive via API on creation of an energy sink. + """ + pass -# Properties to receive via API on update -class EnergySinkUpdate(EnergySinkBase): - name: Optional[str] = None - description: Optional[str] = None +class EnergySinkUpdate(EnergySinkBase, EnergyComponentUpdate): + """ + Properties to receive via API on update of an energy sink. + """ + commodity: Optional[str] = None -class EnergySinkInDBBase(EnergySinkBase): - id: Optional[int] = None +class EnergySink(EnergySinkBase): + """ + Properties to return via API for an energy sink. + """ + component: EnergyComponent + commodity: EnergyCommodity class Config: orm_mode = True - - -# Additional properties to return via API -class EnergySink(EnergySinkInDBBase): - pass - - -# Additional properties stored in DB -class EnergySinkInDB(EnergySinkInDBBase): - description: Optional[str] = None diff --git a/ensysmod/schemas/energy_source.py b/ensysmod/schemas/energy_source.py index 583c4de..25fff6c 100644 --- a/ensysmod/schemas/energy_source.py +++ b/ensysmod/schemas/energy_source.py @@ -2,36 +2,38 @@ from pydantic import BaseModel +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyComponentCreate, EnergyComponent, EnergyComponentUpdate, EnergyCommodity + -# Shared properties class EnergySourceBase(BaseModel): - name: Optional[str] = None + """ + Shared properties for an energy source. Used as a base class for all schemas. + """ + commodity: str + type = EnergyComponentType.SOURCE -# Properties to receive via API on creation -class EnergySourceCreate(EnergySourceBase): - name: str - description: Optional[str] = None +class EnergySourceCreate(EnergySourceBase, EnergyComponentCreate): + """ + Properties to receive via API on creation of an energy source. + """ + pass -# Properties to receive via API on update -class EnergySourceUpdate(EnergySourceBase): - name: Optional[str] = None - description: Optional[str] = None +class EnergySourceUpdate(EnergySourceBase, EnergyComponentUpdate): + """ + Properties to receive via API on update of an energy source. + """ + commodity: Optional[str] = None -class EnergySourceInDBBase(EnergySourceBase): - id: Optional[int] = None +class EnergySource(EnergySourceBase): + """ + Properties to return via API for an energy source. + """ + component: EnergyComponent + commodity: EnergyCommodity class Config: orm_mode = True - - -# Additional properties to return via API -class EnergySource(EnergySourceInDBBase): - pass - - -# Additional properties stored in DB -class EnergySourceInDB(EnergySourceInDBBase): - description: Optional[str] = None diff --git a/ensysmod/schemas/energy_storage.py b/ensysmod/schemas/energy_storage.py index 87a5115..2fef665 100644 --- a/ensysmod/schemas/energy_storage.py +++ b/ensysmod/schemas/energy_storage.py @@ -2,36 +2,38 @@ from pydantic import BaseModel +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyComponentCreate, EnergyComponent, EnergyComponentUpdate, EnergyCommodity + -# Shared properties class EnergyStorageBase(BaseModel): - name: Optional[str] = None + """ + Shared properties for an energy storage. Used as a base class for all schemas. + """ + commodity: str + type = EnergyComponentType.STORAGE -# Properties to receive via API on creation -class EnergyStorageCreate(EnergyStorageBase): - name: str - description: Optional[str] = None +class EnergyStorageCreate(EnergyStorageBase, EnergyComponentCreate): + """ + Properties to receive via API on creation of an energy storage. + """ + pass -# Properties to receive via API on update -class EnergyStorageUpdate(EnergyStorageBase): - name: Optional[str] = None - description: Optional[str] = None +class EnergyStorageUpdate(EnergyStorageBase, EnergyComponentUpdate): + """ + Properties to receive via API on update of an energy storage. + """ + commodity: Optional[str] = None -class EnergyStorageInDBBase(EnergyStorageBase): - id: Optional[int] = None +class EnergyStorage(EnergyStorageBase): + """ + Properties to return via API for an energy storage. + """ + component: EnergyComponent + commodity: EnergyCommodity class Config: orm_mode = True - - -# Additional properties to return via API -class EnergyStorage(EnergyStorageInDBBase): - pass - - -# Additional properties stored in DB -class EnergyStorageInDB(EnergyStorageInDBBase): - description: Optional[str] = None diff --git a/ensysmod/schemas/energy_transmission.py b/ensysmod/schemas/energy_transmission.py new file mode 100644 index 0000000..9d7633c --- /dev/null +++ b/ensysmod/schemas/energy_transmission.py @@ -0,0 +1,39 @@ +from typing import Optional + +from pydantic import BaseModel + +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyComponentCreate, EnergyComponent, EnergyComponentUpdate, EnergyCommodity + + +class EnergyTransmissionBase(BaseModel): + """ + Shared properties for an energy transmission. Used as a base class for all schemas. + """ + commodity: str + type = EnergyComponentType.TRANSMISSION + + +class EnergyTransmissionCreate(EnergyTransmissionBase, EnergyComponentCreate): + """ + Properties to receive via API on creation of an energy transmission. + """ + pass + + +class EnergyTransmissionUpdate(EnergyTransmissionBase, EnergyComponentUpdate): + """ + Properties to receive via API on update of an energy transmission. + """ + commodity: Optional[str] = None + + +class EnergyTransmission(EnergyTransmissionBase): + """ + Properties to return via API for an energy transmission. + """ + component: EnergyComponent + commodity: EnergyCommodity + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/capacity.py b/ensysmod/schemas/ts_capacity.py similarity index 100% rename from ensysmod/schemas/capacity.py rename to ensysmod/schemas/ts_capacity.py diff --git a/ensysmod/schemas/consumption.py b/ensysmod/schemas/ts_consumption.py similarity index 100% rename from ensysmod/schemas/consumption.py rename to ensysmod/schemas/ts_consumption.py diff --git a/ensysmod/schemas/generation.py b/ensysmod/schemas/ts_generation.py similarity index 100% rename from ensysmod/schemas/generation.py rename to ensysmod/schemas/ts_generation.py diff --git a/tests/api/test_datasets.py b/tests/api/test_datasets.py new file mode 100644 index 0000000..176f1ff --- /dev/null +++ b/tests/api/test_datasets.py @@ -0,0 +1,86 @@ +from typing import Dict + +from fastapi import status +from fastapi.encoders import jsonable_encoder +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.schemas import DatasetCreate, DatasetUpdate, Dataset +from tests.utils.utils import random_lower_string + + +def get_random_dataset_create() -> DatasetCreate: + dataset_name = "DS " + random_lower_string() + dataset_description = "DS desc " + random_lower_string() + return DatasetCreate(name=dataset_name, description=dataset_description) + + +def get_random_existing_dataset(db: Session) -> Dataset: + create_request = get_random_dataset_create() + return crud.dataset.create(db=db, obj_in=create_request) + + +def test_create_dataset(client: TestClient, normal_user_headers: Dict[str, str]): + """ + Test creating a dataset. + """ + # Create a dataset + create_request = get_random_dataset_create() + + response = client.post( + "/datasets/", + headers=normal_user_headers, + data=create_request.json() + ) + assert response.status_code == status.HTTP_200_OK + + created_dataset = response.json() + assert created_dataset['name'] == create_request.name + assert created_dataset['description'] == create_request.description + + +def test_create_existing_dataset(db: Session, client: TestClient, normal_user_headers: Dict[str, str]): + """ + Test creating an existing dataset. + """ + existing_dataset = get_random_existing_dataset(db) + create_request = DatasetCreate(**jsonable_encoder(existing_dataset)) + response = client.post( + "/datasets/", + headers=normal_user_headers, + data=create_request.json() + ) + assert response.status_code == status.HTTP_409_CONFLICT + + +def test_update_existing_dataset(db: Session, client: TestClient, normal_user_headers: Dict[str, str]): + """ + Test updating an existing dataset. + """ + existing_dataset = get_random_existing_dataset(db) + update_request = DatasetUpdate(**jsonable_encoder(existing_dataset)) + new_description = random_lower_string() + update_request.description = new_description + response = client.put( + f"/datasets/{existing_dataset.id}", + headers=normal_user_headers, + data=update_request.json() + ) + assert response.status_code == status.HTTP_200_OK + + updated_dataset = response.json() + assert updated_dataset['name'] == update_request.name + assert updated_dataset['description'] == update_request.description + + +def test_delete_existing_dataset(db: Session, client: TestClient, normal_user_headers: Dict[str, str]): + """ + Test deleting an existing dataset. + """ + existing_dataset = get_random_existing_dataset(db) + response = client.delete( + f"/datasets/{existing_dataset.id}", + headers=normal_user_headers + ) + assert response.status_code == status.HTTP_200_OK diff --git a/tests/api/test_energy_commodities.py b/tests/api/test_energy_commodities.py new file mode 100644 index 0000000..f3c96a9 --- /dev/null +++ b/tests/api/test_energy_commodities.py @@ -0,0 +1,51 @@ +from typing import Dict + +from fastapi import status +from fastapi.encoders import jsonable_encoder +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.schemas import EnergyCommodityCreate, EnergyCommodity +from tests.api.test_datasets import get_random_existing_dataset +from tests.utils.utils import random_lower_string + + +def get_random_energy_commodity_create(db: Session) -> EnergyCommodityCreate: + dataset = get_random_existing_dataset(db) + return EnergyCommodityCreate(name=f"EnergyCommodity-{dataset.id}-" + random_lower_string(), + ref_dataset=dataset.id, + description="EnergyCommodity description", + unit="kWh") + + +def get_random_existing_energy_commodity(db: Session) -> EnergyCommodity: + create_request = get_random_energy_commodity_create(db) + return crud.energy_commodity.create(db=db, obj_in=create_request) + + +def test_create_energy_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy commodity. + """ + create_request = get_random_energy_commodity_create(db) + response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_commodity = response.json() + assert created_commodity["name"] == create_request.name + assert created_commodity["dataset"]["id"] == create_request.ref_dataset + assert created_commodity["description"] == create_request.description + assert created_commodity["unit"] == create_request.unit + + +def test_create_existing_energy_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing energy commodity. + """ + existing_commodity = get_random_existing_energy_commodity(db) + create_request = EnergyCommodityCreate(**jsonable_encoder(existing_commodity)) + response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + +# TODO Add more test cases diff --git a/tests/api/test_energy_conversions.py b/tests/api/test_energy_conversions.py new file mode 100644 index 0000000..f81998c --- /dev/null +++ b/tests/api/test_energy_conversions.py @@ -0,0 +1,45 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyConversionCreate, EnergyConversion +from tests.api.test_datasets import get_random_existing_dataset +from tests.api.test_energy_commodities import get_random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def get_random_energy_conversion_create(db: Session) -> EnergyConversionCreate: + dataset = get_random_existing_dataset(db) + commodity = get_random_existing_energy_commodity(db) + return EnergyConversionCreate( + ref_dataset=dataset.id, + name=f"Energy Conversion {random_lower_string()}", + description="Description", + commodity_unit=commodity.name, + ) + + +def get_random_existing_energy_conversion(db: Session) -> EnergyConversion: + create_request = get_random_energy_conversion_create(db) + return crud.energy_conversion.create(db=db, obj_in=create_request) + + +def test_create_energy_conversion(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy conversion. + """ + create_request = get_random_energy_conversion_create(db) + response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_commodity = response.json() + assert created_commodity["component"]["name"] == create_request.name + assert created_commodity["component"]["description"] == create_request.description + assert created_commodity["component"]["type"] == EnergyComponentType.CONVERSION.value + assert created_commodity["commodity_unit"]["name"] == create_request.commodity_unit + +# TODO Add more test cases diff --git a/tests/api/test_energy_sinks.py b/tests/api/test_energy_sinks.py new file mode 100644 index 0000000..08a4ba5 --- /dev/null +++ b/tests/api/test_energy_sinks.py @@ -0,0 +1,45 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergySinkCreate, EnergySink +from tests.api.test_datasets import get_random_existing_dataset +from tests.api.test_energy_commodities import get_random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def get_random_energy_sink_create(db: Session) -> EnergySinkCreate: + dataset = get_random_existing_dataset(db) + commodity = get_random_existing_energy_commodity(db) + return EnergySinkCreate( + ref_dataset=dataset.id, + name=f"Energy Sink {random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def get_random_existing_energy_sink(db: Session) -> EnergySink: + create_request = get_random_energy_sink_create(db) + return crud.energy_sink.create(db=db, obj_in=create_request) + + +def test_create_energy_sink(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy sink. + """ + create_request = get_random_energy_sink_create(db) + response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_commodity = response.json() + assert created_commodity["component"]["name"] == create_request.name + assert created_commodity["component"]["description"] == create_request.description + assert created_commodity["component"]["type"] == EnergyComponentType.SINK.value + assert created_commodity["commodity"]["name"] == create_request.commodity + +# TODO Add more test cases diff --git a/tests/api/test_energy_sources.py b/tests/api/test_energy_sources.py new file mode 100644 index 0000000..6876be5 --- /dev/null +++ b/tests/api/test_energy_sources.py @@ -0,0 +1,45 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergySourceCreate, EnergySource +from tests.api.test_datasets import get_random_existing_dataset +from tests.api.test_energy_commodities import get_random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def get_random_energy_source_create(db: Session) -> EnergySourceCreate: + dataset = get_random_existing_dataset(db) + commodity = get_random_existing_energy_commodity(db) + return EnergySourceCreate( + ref_dataset=dataset.id, + name=f"Energy Source {random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def get_random_existing_energy_source(db: Session) -> EnergySource: + create_request = get_random_energy_source_create(db) + return crud.energy_source.create(db=db, obj_in=create_request) + + +def test_create_energy_source(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy source. + """ + create_request = get_random_energy_source_create(db) + response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_commodity = response.json() + assert created_commodity["component"]["name"] == create_request.name + assert created_commodity["component"]["description"] == create_request.description + assert created_commodity["component"]["type"] == EnergyComponentType.SOURCE.value + assert created_commodity["commodity"]["name"] == create_request.commodity + +# TODO Add more test cases diff --git a/tests/api/test_energy_storages.py b/tests/api/test_energy_storages.py new file mode 100644 index 0000000..14e2fd7 --- /dev/null +++ b/tests/api/test_energy_storages.py @@ -0,0 +1,45 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyStorageCreate, EnergyStorage +from tests.api.test_datasets import get_random_existing_dataset +from tests.api.test_energy_commodities import get_random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def get_random_energy_storage_create(db: Session) -> EnergyStorageCreate: + dataset = get_random_existing_dataset(db) + commodity = get_random_existing_energy_commodity(db) + return EnergyStorageCreate( + ref_dataset=dataset.id, + name=f"Energy Storage {random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def get_random_existing_energy_storage(db: Session) -> EnergyStorage: + create_request = get_random_energy_storage_create(db) + return crud.energy_storage.create(db=db, obj_in=create_request) + + +def test_create_energy_storage(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy storage. + """ + create_request = get_random_energy_storage_create(db) + response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_commodity = response.json() + assert created_commodity["component"]["name"] == create_request.name + assert created_commodity["component"]["description"] == create_request.description + assert created_commodity["component"]["type"] == EnergyComponentType.STORAGE.value + assert created_commodity["commodity"]["name"] == create_request.commodity + +# TODO Add more test cases diff --git a/tests/api/test_energy_transmissions.py b/tests/api/test_energy_transmissions.py new file mode 100644 index 0000000..1b360f3 --- /dev/null +++ b/tests/api/test_energy_transmissions.py @@ -0,0 +1,45 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyTransmissionCreate, EnergyTransmission +from tests.api.test_datasets import get_random_existing_dataset +from tests.api.test_energy_commodities import get_random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def get_random_energy_transmission_create(db: Session) -> EnergyTransmissionCreate: + dataset = get_random_existing_dataset(db) + commodity = get_random_existing_energy_commodity(db) + return EnergyTransmissionCreate( + ref_dataset=dataset.id, + name=f"Energy Transmission {random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def get_random_existing_energy_transmission(db: Session) -> EnergyTransmission: + create_request = get_random_energy_transmission_create(db) + return crud.energy_transmission.create(db=db, obj_in=create_request) + + +def test_create_energy_transmission(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy transmission. + """ + create_request = get_random_energy_transmission_create(db) + response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_commodity = response.json() + assert created_commodity["component"]["name"] == create_request.name + assert created_commodity["component"]["description"] == create_request.description + assert created_commodity["component"]["type"] == EnergyComponentType.TRANSMISSION.value + assert created_commodity["commodity"]["name"] == create_request.commodity + +# TODO Add more test cases diff --git a/tests/conftest.py b/tests/conftest.py index af7deb4..6fb2fba 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ from ensysmod.app import app from ensysmod.database.session import SessionLocal +from tests.utils.utils import authentication_token_from_username, create_random_user @pytest.fixture(scope="function") @@ -22,3 +23,10 @@ def db() -> Generator: def client() -> Generator: with TestClient(app) as c: yield c + + +@pytest.fixture(scope="module") +def normal_user_headers(client: TestClient) -> Generator: + db = SessionLocal() + user = create_random_user(db) + yield authentication_token_from_username(db=db, client=client, username=user.username) diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 654761b..5b24a21 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -1,6 +1,53 @@ import random import string +from typing import Dict + +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import User +from ensysmod.schemas import UserCreate, UserUpdate def random_lower_string() -> str: return "".join(random.choices(string.ascii_lowercase, k=32)) + + +def user_authentication_headers( + *, client: TestClient, username: str, password: str +) -> Dict[str, str]: + data = {"username": username, "password": password} + + r = client.post(f"/auth/login", data=data, headers={"content-type": "application/x-www-form-urlencoded"}) + response = r.json() + auth_token = response["access_token"] + headers = {"Authorization": f"Bearer {auth_token}"} + return headers + + +def create_random_user(db: Session) -> User: + username = random_lower_string() + password = random_lower_string() + user_in = UserCreate(username=username, password=password) + user = crud.user.create(db=db, obj_in=user_in) + return user + + +def authentication_token_from_username( + *, client: TestClient, username: str, db: Session +) -> Dict[str, str]: + """ + Return a valid token for the user with given username. + If the user doesn't exist it is created first. + """ + password = random_lower_string() + user = crud.user.get_by_username(db, username=username) + if not user: + user_in_create = UserCreate(username=username, password=password) + crud.user.create(db, obj_in=user_in_create) + else: + user_in_update = UserUpdate(password=password) + crud.user.update(db, db_obj=user, obj_in=user_in_update) + + return user_authentication_headers(client=client, username=username, password=password) From b891997df1de04387dbbec71ed70d62269f5b972 Mon Sep 17 00:00:00 2001 From: Melanie Ecker Date: Sun, 5 Dec 2021 15:24:53 +0100 Subject: [PATCH 07/22] Added testcases --- tests/api/test_energy_commodities.py | 11 ++++++- tests/api/test_energy_conversions.py | 39 +++++++++++++++++++++---- tests/api/test_energy_sinks.py | 40 ++++++++++++++++++++++---- tests/api/test_energy_sources.py | 39 +++++++++++++++++++++---- tests/api/test_energy_storages.py | 38 ++++++++++++++++++++---- tests/api/test_energy_transmissions.py | 38 ++++++++++++++++++++---- 6 files changed, 179 insertions(+), 26 deletions(-) diff --git a/tests/api/test_energy_commodities.py b/tests/api/test_energy_commodities.py index f3c96a9..3f58b60 100644 --- a/tests/api/test_energy_commodities.py +++ b/tests/api/test_energy_commodities.py @@ -48,4 +48,13 @@ def test_create_existing_energy_commodity(client: TestClient, normal_user_header response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT -# TODO Add more test cases +def test_create_energy_commodity_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy commodity. + """ + create_request = get_random_energy_commodity_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +# TODO Add more test cases \ No newline at end of file diff --git a/tests/api/test_energy_conversions.py b/tests/api/test_energy_conversions.py index f81998c..e12dc78 100644 --- a/tests/api/test_energy_conversions.py +++ b/tests/api/test_energy_conversions.py @@ -1,6 +1,7 @@ from typing import Dict from fastapi import status +from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -36,10 +37,38 @@ def test_create_energy_conversion(client: TestClient, normal_user_headers: Dict[ response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK - created_commodity = response.json() - assert created_commodity["component"]["name"] == create_request.name - assert created_commodity["component"]["description"] == create_request.description - assert created_commodity["component"]["type"] == EnergyComponentType.CONVERSION.value - assert created_commodity["commodity_unit"]["name"] == create_request.commodity_unit + created_conversion = response.json() + assert created_conversion["component"]["name"] == create_request.name + assert created_conversion["component"]["description"] == create_request.description + assert created_conversion["component"]["type"] == EnergyComponentType.CONVERSION.value + assert created_conversion["commodity_unit"]["name"] == create_request.commodity_unit + +def test_create_existing_energy_conversion(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing energy conversion. + """ + create_request = get_random_energy_conversion_create(db) + response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + +def test_create_energy_conversion_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy conversion. + """ + create_request = get_random_energy_conversion_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +def test_create_energy_conversion_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy conversion. + """ + create_request = get_random_energy_conversion_create(db) + create_request.commodity_unit = "0" # ungültige Anfrage + response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND # TODO Add more test cases diff --git a/tests/api/test_energy_sinks.py b/tests/api/test_energy_sinks.py index 08a4ba5..5e40a5c 100644 --- a/tests/api/test_energy_sinks.py +++ b/tests/api/test_energy_sinks.py @@ -1,6 +1,7 @@ from typing import Dict from fastapi import status +from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -36,10 +37,39 @@ def test_create_energy_sink(client: TestClient, normal_user_headers: Dict[str, s response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK - created_commodity = response.json() - assert created_commodity["component"]["name"] == create_request.name - assert created_commodity["component"]["description"] == create_request.description - assert created_commodity["component"]["type"] == EnergyComponentType.SINK.value - assert created_commodity["commodity"]["name"] == create_request.commodity + created_sinks = response.json() + assert created_sinks["component"]["name"] == create_request.name + assert created_sinks["component"]["description"] == create_request.description + assert created_sinks["component"]["type"] == EnergyComponentType.SINK.value + assert created_sinks["commodity"]["name"] == create_request.commodity + +def test_create_existing_energy_sink(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing energy sink. + """ + create_request = get_random_energy_sink_create(db) + response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + +def test_create_energy_sink_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy sink. + """ + create_request = get_random_energy_sink_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +def test_create_energy_sink_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy sink. + """ + create_request = get_random_energy_sink_create(db) + create_request.commodity = "0" # ungültige Anfrage + response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + # TODO Add more test cases diff --git a/tests/api/test_energy_sources.py b/tests/api/test_energy_sources.py index 6876be5..126100f 100644 --- a/tests/api/test_energy_sources.py +++ b/tests/api/test_energy_sources.py @@ -1,6 +1,7 @@ from typing import Dict from fastapi import status +from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -36,10 +37,38 @@ def test_create_energy_source(client: TestClient, normal_user_headers: Dict[str, response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK - created_commodity = response.json() - assert created_commodity["component"]["name"] == create_request.name - assert created_commodity["component"]["description"] == create_request.description - assert created_commodity["component"]["type"] == EnergyComponentType.SOURCE.value - assert created_commodity["commodity"]["name"] == create_request.commodity + created_source = response.json() + assert created_source["component"]["name"] == create_request.name + assert created_source["component"]["description"] == create_request.description + assert created_source["component"]["type"] == EnergyComponentType.SOURCE.value + assert created_source["commodity"]["name"] == create_request.commodity + +def test_create_existing_energy_source(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing energy source. + """ + create_request = get_random_energy_source_create(db) + response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + +def test_create_energy_source_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy source. + """ + create_request = get_random_energy_source_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +def test_create_energy_source_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy source. + """ + create_request = get_random_energy_source_create(db) + create_request.commodity = "0" # ungültige Anfrage + response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND # TODO Add more test cases diff --git a/tests/api/test_energy_storages.py b/tests/api/test_energy_storages.py index 14e2fd7..7cad0c1 100644 --- a/tests/api/test_energy_storages.py +++ b/tests/api/test_energy_storages.py @@ -36,10 +36,38 @@ def test_create_energy_storage(client: TestClient, normal_user_headers: Dict[str response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK - created_commodity = response.json() - assert created_commodity["component"]["name"] == create_request.name - assert created_commodity["component"]["description"] == create_request.description - assert created_commodity["component"]["type"] == EnergyComponentType.STORAGE.value - assert created_commodity["commodity"]["name"] == create_request.commodity + created_storage = response.json() + assert created_storage["component"]["name"] == create_request.name + assert created_storage["component"]["description"] == create_request.description + assert created_storage["component"]["type"] == EnergyComponentType.STORAGE.value + assert created_storage["commodity"]["name"] == create_request.commodity + +def test_create_existing_energy_storage(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing energy storage. + """ + create_request = get_random_energy_storage_create(db) + response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + +def test_create_energy_storage_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy storage. + """ + create_request = get_random_energy_storage_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +def test_create_energy_storage_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy storage. + """ + create_request = get_random_energy_storage_create(db) + create_request.commodity = "0" # ungültige Anfrage + response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND # TODO Add more test cases diff --git a/tests/api/test_energy_transmissions.py b/tests/api/test_energy_transmissions.py index 1b360f3..3855956 100644 --- a/tests/api/test_energy_transmissions.py +++ b/tests/api/test_energy_transmissions.py @@ -36,10 +36,38 @@ def test_create_energy_transmission(client: TestClient, normal_user_headers: Dic response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK - created_commodity = response.json() - assert created_commodity["component"]["name"] == create_request.name - assert created_commodity["component"]["description"] == create_request.description - assert created_commodity["component"]["type"] == EnergyComponentType.TRANSMISSION.value - assert created_commodity["commodity"]["name"] == create_request.commodity + created_transmission = response.json() + assert created_transmission["component"]["name"] == create_request.name + assert created_transmission["component"]["description"] == create_request.description + assert created_transmission["component"]["type"] == EnergyComponentType.TRANSMISSION.value + assert created_transmission["commodity"]["name"] == create_request.commodity + +def test_create_existing_energy_transmission(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing energy transmission. + """ + create_request = get_random_energy_transmission_create(db) + response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + +def test_create_energy_transmission_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy transmission. + """ + create_request = get_random_energy_transmission_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +def test_create_energy_transmission_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a energy transmission. + """ + create_request = get_random_energy_transmission_create(db) + create_request.commodity = "0" # ungültige Anfrage + response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND # TODO Add more test cases From 713369b5a21293e124a310071e63fee50fac7566 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Sun, 5 Dec 2021 16:17:13 +0100 Subject: [PATCH 08/22] Fixed linting issues --- tests/api/test_energy_commodities.py | 5 +++-- tests/api/test_energy_conversions.py | 11 +++++++---- tests/api/test_energy_sinks.py | 9 +++++---- tests/api/test_energy_sources.py | 8 +++++--- tests/api/test_energy_storages.py | 7 +++++-- tests/api/test_energy_transmissions.py | 13 +++++++++---- tests/utils/utils.py | 2 +- 7 files changed, 35 insertions(+), 20 deletions(-) diff --git a/tests/api/test_energy_commodities.py b/tests/api/test_energy_commodities.py index 3f58b60..b783bd6 100644 --- a/tests/api/test_energy_commodities.py +++ b/tests/api/test_energy_commodities.py @@ -48,13 +48,14 @@ def test_create_existing_energy_commodity(client: TestClient, normal_user_header response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT + def test_create_energy_commodity_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy commodity. """ create_request = get_random_energy_commodity_create(db) - create_request.ref_dataset = 0 # ungültige Anfrage + create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND -# TODO Add more test cases \ No newline at end of file +# TODO Add more test cases diff --git a/tests/api/test_energy_conversions.py b/tests/api/test_energy_conversions.py index e12dc78..62b4410 100644 --- a/tests/api/test_energy_conversions.py +++ b/tests/api/test_energy_conversions.py @@ -1,7 +1,6 @@ from typing import Dict from fastapi import status -from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -43,6 +42,7 @@ def test_create_energy_conversion(client: TestClient, normal_user_headers: Dict[ assert created_conversion["component"]["type"] == EnergyComponentType.CONVERSION.value assert created_conversion["commodity_unit"]["name"] == create_request.commodity_unit + def test_create_existing_energy_conversion(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a existing energy conversion. @@ -53,21 +53,24 @@ def test_create_existing_energy_conversion(client: TestClient, normal_user_heade response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT + def test_create_energy_conversion_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy conversion. """ create_request = get_random_energy_conversion_create(db) - create_request.ref_dataset = 0 # ungültige Anfrage + create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND -def test_create_energy_conversion_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + +def test_create_energy_conversion_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], + db: Session): """ Test creating a energy conversion. """ create_request = get_random_energy_conversion_create(db) - create_request.commodity_unit = "0" # ungültige Anfrage + create_request.commodity_unit = "0" # ungültige Anfrage response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_sinks.py b/tests/api/test_energy_sinks.py index 5e40a5c..73cfb60 100644 --- a/tests/api/test_energy_sinks.py +++ b/tests/api/test_energy_sinks.py @@ -1,7 +1,6 @@ from typing import Dict from fastapi import status -from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -43,6 +42,7 @@ def test_create_energy_sink(client: TestClient, normal_user_headers: Dict[str, s assert created_sinks["component"]["type"] == EnergyComponentType.SINK.value assert created_sinks["commodity"]["name"] == create_request.commodity + def test_create_existing_energy_sink(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a existing energy sink. @@ -53,23 +53,24 @@ def test_create_existing_energy_sink(client: TestClient, normal_user_headers: Di response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT + def test_create_energy_sink_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy sink. """ create_request = get_random_energy_sink_create(db) - create_request.ref_dataset = 0 # ungültige Anfrage + create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND + def test_create_energy_sink_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy sink. """ create_request = get_random_energy_sink_create(db) - create_request.commodity = "0" # ungültige Anfrage + create_request.commodity = "0" # ungültige Anfrage response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND - # TODO Add more test cases diff --git a/tests/api/test_energy_sources.py b/tests/api/test_energy_sources.py index 126100f..e49197b 100644 --- a/tests/api/test_energy_sources.py +++ b/tests/api/test_energy_sources.py @@ -1,7 +1,6 @@ from typing import Dict from fastapi import status -from fastapi.encoders import jsonable_encoder from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -43,6 +42,7 @@ def test_create_energy_source(client: TestClient, normal_user_headers: Dict[str, assert created_source["component"]["type"] == EnergyComponentType.SOURCE.value assert created_source["commodity"]["name"] == create_request.commodity + def test_create_existing_energy_source(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a existing energy source. @@ -53,21 +53,23 @@ def test_create_existing_energy_source(client: TestClient, normal_user_headers: response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT + def test_create_energy_source_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy source. """ create_request = get_random_energy_source_create(db) - create_request.ref_dataset = 0 # ungültige Anfrage + create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND + def test_create_energy_source_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy source. """ create_request = get_random_energy_source_create(db) - create_request.commodity = "0" # ungültige Anfrage + create_request.commodity = "0" # ungültige Anfrage response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_storages.py b/tests/api/test_energy_storages.py index 7cad0c1..8b36801 100644 --- a/tests/api/test_energy_storages.py +++ b/tests/api/test_energy_storages.py @@ -42,6 +42,7 @@ def test_create_energy_storage(client: TestClient, normal_user_headers: Dict[str assert created_storage["component"]["type"] == EnergyComponentType.STORAGE.value assert created_storage["commodity"]["name"] == create_request.commodity + def test_create_existing_energy_storage(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a existing energy storage. @@ -52,21 +53,23 @@ def test_create_existing_energy_storage(client: TestClient, normal_user_headers: response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT + def test_create_energy_storage_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy storage. """ create_request = get_random_energy_storage_create(db) - create_request.ref_dataset = 0 # ungültige Anfrage + create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND + def test_create_energy_storage_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy storage. """ create_request = get_random_energy_storage_create(db) - create_request.commodity = "0" # ungültige Anfrage + create_request.commodity = "0" # ungültige Anfrage response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_transmissions.py b/tests/api/test_energy_transmissions.py index 3855956..5438c90 100644 --- a/tests/api/test_energy_transmissions.py +++ b/tests/api/test_energy_transmissions.py @@ -42,6 +42,7 @@ def test_create_energy_transmission(client: TestClient, normal_user_headers: Dic assert created_transmission["component"]["type"] == EnergyComponentType.TRANSMISSION.value assert created_transmission["commodity"]["name"] == create_request.commodity + def test_create_existing_energy_transmission(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a existing energy transmission. @@ -52,21 +53,25 @@ def test_create_existing_energy_transmission(client: TestClient, normal_user_hea response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT -def test_create_energy_transmission_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + +def test_create_energy_transmission_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], + db: Session): """ Test creating a energy transmission. """ create_request = get_random_energy_transmission_create(db) - create_request.ref_dataset = 0 # ungültige Anfrage + create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND -def test_create_energy_transmission_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + +def test_create_energy_transmission_unknown_commodity(client: TestClient, normal_user_headers: Dict[str, str], + db: Session): """ Test creating a energy transmission. """ create_request = get_random_energy_transmission_create(db) - create_request.commodity = "0" # ungültige Anfrage + create_request.commodity = "0" # ungültige Anfrage response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 5b24a21..5ba547b 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -19,7 +19,7 @@ def user_authentication_headers( ) -> Dict[str, str]: data = {"username": username, "password": password} - r = client.post(f"/auth/login", data=data, headers={"content-type": "application/x-www-form-urlencoded"}) + r = client.post("/auth/login", data=data, headers={"content-type": "application/x-www-form-urlencoded"}) response = r.json() auth_token = response["access_token"] headers = {"Authorization": f"Bearer {auth_token}"} From 38ea9966e3a6faf3992164059ef9572dc3e9b734 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Sun, 5 Dec 2021 20:37:33 +0100 Subject: [PATCH 09/22] Added unique constraints for name columns --- ensysmod/model/energy_commodity.py | 9 +++++++-- ensysmod/model/energy_component.py | 8 +++++++- ensysmod/model/region.py | 9 +++++++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ensysmod/model/energy_commodity.py b/ensysmod/model/energy_commodity.py index d05eaa3..3a65335 100644 --- a/ensysmod/model/energy_commodity.py +++ b/ensysmod/model/energy_commodity.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -7,7 +7,7 @@ class EnergyCommodity(Base): id = Column(Integer, primary_key=True, index=True) ref_dataset = Column(Integer, ForeignKey("dataset.id"), index=True, nullable=False) - name = Column(String, unique=True, index=True, nullable=False) + name = Column(String, index=True, nullable=False) description = Column(String, nullable=True) unit = Column(String, nullable=False) @@ -18,3 +18,8 @@ class EnergyCommodity(Base): energy_sinks = relationship("EnergySink", back_populates="commodity") energy_storages = relationship("EnergyStorage", back_populates="commodity") energy_transmissions = relationship("EnergyTransmission", back_populates="commodity") + + # table constraints + __table_args__ = ( + UniqueConstraint("ref_dataset", "name", name="_commodity_name_dataset_uc"), + ) diff --git a/ensysmod/model/energy_component.py b/ensysmod/model/energy_component.py index ba1d52e..02d77c9 100644 --- a/ensysmod/model/energy_component.py +++ b/ensysmod/model/energy_component.py @@ -1,6 +1,6 @@ import enum -from sqlalchemy import Column, Integer, String, Boolean, DECIMAL, ForeignKey, Enum +from sqlalchemy import Column, Integer, String, Boolean, DECIMAL, ForeignKey, Enum, UniqueConstraint, CheckConstraint from ensysmod.database.base_class import Base @@ -49,3 +49,9 @@ class EnergyComponent(Base): economic_lifetime = Column(Integer, nullable=False, default=10) # constraint capacityVariableDomain + + # table constraints + __table_args__ = ( + UniqueConstraint("ref_dataset", "name", name="_commodity_name_dataset_uc"), + ) + diff --git a/ensysmod/model/region.py b/ensysmod/model/region.py index c3874e3..88fe85f 100644 --- a/ensysmod/model/region.py +++ b/ensysmod/model/region.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint from ensysmod.database.base_class import Base @@ -11,4 +11,9 @@ class Region(Base): """ id = Column(Integer, primary_key=True, index=True) ref_dataset = Column(Integer, ForeignKey("dataset.id"), index=True, nullable=False) - name = Column(String, unique=True, index=True, nullable=False) + name = Column(String, index=True, nullable=False) + + # table constraints + __table_args__ = ( + UniqueConstraint("ref_dataset", "name", name="_region_dataset_name_uc"), + ) From 0aafc8d458aa286201320797bd67438cfeeeab0f Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Sun, 5 Dec 2021 22:11:51 +0100 Subject: [PATCH 10/22] Added region endpoint --- ensysmod/api/api.py | 3 +- ensysmod/api/endpoints/regions.py | 82 ++++++++++++++++++++++++++++ ensysmod/crud/region.py | 13 ++++- ensysmod/model/region.py | 4 ++ ensysmod/schemas/__init__.py | 2 +- ensysmod/schemas/energy_component.py | 1 - ensysmod/schemas/region.py | 38 ++++++------- tests/api/test_regions.py | 57 +++++++++++++++++++ 8 files changed, 175 insertions(+), 25 deletions(-) create mode 100644 ensysmod/api/endpoints/regions.py create mode 100644 tests/api/test_regions.py diff --git a/ensysmod/api/api.py b/ensysmod/api/api.py index a0625a9..283e93d 100644 --- a/ensysmod/api/api.py +++ b/ensysmod/api/api.py @@ -1,12 +1,13 @@ from fastapi import APIRouter from .endpoints import users, authentication, energy_sources, datasets, energy_commodities, energy_sinks, \ - energy_storages, energy_transmissions, energy_conversions + energy_storages, energy_transmissions, energy_conversions, regions api_router = APIRouter() api_router.include_router(authentication.router, prefix="/auth", tags=["Authentication"]) api_router.include_router(users.router, prefix="/users", tags=["Users"]) api_router.include_router(datasets.router, prefix="/datasets", tags=["Datasets"]) +api_router.include_router(regions.router, prefix="/regions", tags=["Regions"]) api_router.include_router(energy_commodities.router, prefix="/commodities", tags=["Commodities"]) api_router.include_router(energy_conversions.router, prefix="/conversions", tags=["Energy Conversions"]) api_router.include_router(energy_sinks.router, prefix="/sinks", tags=["Energy Sinks"]) diff --git a/ensysmod/api/endpoints/regions.py b/ensysmod/api/endpoints/regions.py new file mode 100644 index 0000000..8bb641a --- /dev/null +++ b/ensysmod/api/endpoints/regions.py @@ -0,0 +1,82 @@ +from typing import List, Union + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.Region]) +def all_regions(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100, + dataset: Union[None, int] = None) -> List[schemas.Region]: + """ + Retrieve all energy regions. + """ + if dataset is None: + return crud.region.get_multi(db, skip=skip, limit=limit) + else: + return crud.region.get_multi_by_dataset(db, dataset_id=dataset, skip=skip, limit=limit) + + +@router.get("/{region_id}", response_model=schemas.Region) +def get_region(region_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Retrieve a region. + """ + # TODO Check if user has permission for dataset and region + return crud.region.get(db, region_id) + + +@router.post("/", response_model=schemas.Region) +def create_region(request: schemas.RegionCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new region. + """ + dataset = crud.dataset.get(db=db, id=request.ref_dataset) + if dataset is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Dataset {request.ref_dataset} not found!") + + # TODO Check if user has permission for dataset + + existing = crud.region.get_by_dataset_and_name(db=db, dataset_id=request.ref_dataset, name=request.name) + if existing is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"Region {request.name} already for dataset {request.ref_dataset} exists!") + + return crud.region.create(db=db, obj_in=request) + + +@router.put("/{region_id}", response_model=schemas.Region) +def update_region(region_id: int, + request: schemas.RegionUpdate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Update a region. + """ + # TODO Check if user has permission for region + region = crud.region.get(db=db, id=region_id) + if region is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Region {region_id} not found!") + return crud.region.update(db=db, db_obj=region, obj_in=request) + + +@router.delete("/{region_id}", response_model=schemas.Region) +def remove_region(region_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Delete a region. + """ + # TODO Check if user has permission for dataset + return crud.region.remove(db=db, id=region_id) diff --git a/ensysmod/crud/region.py b/ensysmod/crud/region.py index e118b3f..5294f0a 100644 --- a/ensysmod/crud/region.py +++ b/ensysmod/crud/region.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, List from sqlalchemy.orm import Session @@ -9,8 +9,15 @@ # noinspection PyMethodMayBeStatic,PyArgumentList class CRUDRegion(CRUDBase[Region, RegionCreate, RegionUpdate]): - def get_by_name(self, db: Session, *, name: str) -> Optional[Region]: - return db.query(Region).filter(Region.name == name).first() + def get_multi_by_dataset( + self, db: Session, *, skip: int = 0, limit: int = 100, dataset_id: int + ) -> List[Region]: + return db.query(Region) \ + .filter(Region.ref_dataset == dataset_id) \ + .offset(skip).limit(limit).all() + + def get_by_dataset_and_name(self, db: Session, *, dataset_id: int, name: str) -> Optional[Region]: + return db.query(Region).filter(Region.name == name and Region.ref_dataset == dataset_id).first() region = CRUDRegion(Region) diff --git a/ensysmod/model/region.py b/ensysmod/model/region.py index 88fe85f..4f6277a 100644 --- a/ensysmod/model/region.py +++ b/ensysmod/model/region.py @@ -1,4 +1,5 @@ from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint +from sqlalchemy.orm import relationship from ensysmod.database.base_class import Base @@ -13,6 +14,9 @@ class Region(Base): ref_dataset = Column(Integer, ForeignKey("dataset.id"), index=True, nullable=False) name = Column(String, index=True, nullable=False) + # relationships + dataset = relationship("Dataset") + # table constraints __table_args__ = ( UniqueConstraint("ref_dataset", "name", name="_region_dataset_name_uc"), diff --git a/ensysmod/schemas/__init__.py b/ensysmod/schemas/__init__.py index e1731e8..80b0a37 100644 --- a/ensysmod/schemas/__init__.py +++ b/ensysmod/schemas/__init__.py @@ -9,7 +9,7 @@ from .energy_source import EnergySource, EnergySourceCreate, EnergySourceUpdate from .energy_storage import EnergyStorage, EnergyStorageCreate, EnergyStorageUpdate from .energy_transmission import EnergyTransmission, EnergyTransmissionCreate, EnergyTransmissionUpdate -from .region import Region, RegionCreate, RegionUpdate, RegionInDB +from .region import Region, RegionCreate, RegionUpdate from .token import Token, TokenPayload from .ts_capacity import Capacity, CapacityCreate, CapacityUpdate, CapacityInDB from .ts_consumption import Consumption, ConsumptionCreate, ConsumptionUpdate, ConsumptionInDB diff --git a/ensysmod/schemas/energy_component.py b/ensysmod/schemas/energy_component.py index 23d9180..c2470da 100644 --- a/ensysmod/schemas/energy_component.py +++ b/ensysmod/schemas/energy_component.py @@ -28,7 +28,6 @@ class EnergyComponentUpdate(EnergyComponentBase): pass -# Additional properties to return via API class EnergyComponent(EnergyComponentBase): """ Properties to return via API for an energy component. diff --git a/ensysmod/schemas/region.py b/ensysmod/schemas/region.py index 82473cb..c45aad3 100644 --- a/ensysmod/schemas/region.py +++ b/ensysmod/schemas/region.py @@ -2,36 +2,36 @@ from pydantic import BaseModel +from ensysmod.schemas import Dataset + -# Shared properties class RegionBase(BaseModel): - name: Optional[str] = None + """ + Shared properties for a region. Used as a base class for all schemas. + """ + name: str -# Properties to receive via API on creation class RegionCreate(RegionBase): - name: str - parent_region: Optional[str] = None + """ + Properties to receive via API on creation of a region. + """ + ref_dataset: int -# Properties to receive via API on update class RegionUpdate(RegionBase): + """ + Properties to receive via API on update of a region. + """ name: Optional[str] = None - parent_Region: Optional[str] = None -class RegionInDBBase(RegionBase): - id: Optional[int] = None +class Region(RegionBase): + """ + Properties to return via API for a region. + """ + id: int + dataset: Dataset class Config: orm_mode = True - - -# Additional properties to return via API -class Region(RegionInDBBase): - pass - - -# Additional properties stored in DB -class RegionInDB(RegionInDBBase): - parent_region: Optional[str] = None diff --git a/tests/api/test_regions.py b/tests/api/test_regions.py new file mode 100644 index 0000000..0e8a0c0 --- /dev/null +++ b/tests/api/test_regions.py @@ -0,0 +1,57 @@ +from typing import Dict + +from fastapi import status +from fastapi.encoders import jsonable_encoder +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.schemas import RegionCreate, Region +from tests.api.test_datasets import get_random_existing_dataset +from tests.utils.utils import random_lower_string + + +def get_random_region_create(db: Session) -> RegionCreate: + dataset = get_random_existing_dataset(db) + return RegionCreate(name=f"Region-{dataset.id}-" + random_lower_string(), + ref_dataset=dataset.id) + + +def get_random_existing_region(db: Session) -> Region: + create_request = get_random_region_create(db) + return crud.region.create(db=db, obj_in=create_request) + + +def test_create_region(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a region. + """ + create_request = get_random_region_create(db) + response = client.post("/regions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_200_OK + + created_region = response.json() + assert created_region["name"] == create_request.name + assert created_region["dataset"]["id"] == create_request.ref_dataset + + +def test_create_existing_region(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a existing region. + """ + existing_region = get_random_existing_region(db) + create_request = RegionCreate(**jsonable_encoder(existing_region)) + response = client.post("/regions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_409_CONFLICT + + +def test_create_region_unknown_dataset(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a region. + """ + create_request = get_random_region_create(db) + create_request.ref_dataset = 0 # ungültige Anfrage + response = client.post("/regions/", headers=normal_user_headers, data=create_request.json()) + assert response.status_code == status.HTTP_404_NOT_FOUND + +# TODO Add more test cases From a64ab4c03aea3418c78420f8bb2eb4584fe8e37b Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Sun, 5 Dec 2021 22:33:04 +0100 Subject: [PATCH 11/22] Fixed linting according to flake8 --- ensysmod/model/energy_component.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ensysmod/model/energy_component.py b/ensysmod/model/energy_component.py index 02d77c9..4d8d875 100644 --- a/ensysmod/model/energy_component.py +++ b/ensysmod/model/energy_component.py @@ -1,6 +1,6 @@ import enum -from sqlalchemy import Column, Integer, String, Boolean, DECIMAL, ForeignKey, Enum, UniqueConstraint, CheckConstraint +from sqlalchemy import Column, Integer, String, Boolean, DECIMAL, ForeignKey, Enum, UniqueConstraint from ensysmod.database.base_class import Base @@ -54,4 +54,3 @@ class EnergyComponent(Base): __table_args__ = ( UniqueConstraint("ref_dataset", "name", name="_commodity_name_dataset_uc"), ) - From d03dd1420c923f441d18a0a497cc1b9da8123057 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Mon, 6 Dec 2021 12:21:59 +0100 Subject: [PATCH 12/22] Added 409 response description --- ensysmod/api/endpoints/authentication.py | 5 +++-- ensysmod/api/endpoints/datasets.py | 4 +++- ensysmod/api/endpoints/energy_commodities.py | 3 ++- ensysmod/api/endpoints/energy_conversions.py | 3 ++- ensysmod/api/endpoints/energy_sinks.py | 3 ++- ensysmod/api/endpoints/energy_sources.py | 3 ++- ensysmod/api/endpoints/energy_storages.py | 3 ++- ensysmod/api/endpoints/energy_transmissions.py | 3 ++- ensysmod/api/endpoints/regions.py | 3 ++- tests/api/test_authentication.py | 2 +- 10 files changed, 21 insertions(+), 11 deletions(-) diff --git a/ensysmod/api/endpoints/authentication.py b/ensysmod/api/endpoints/authentication.py index 822549e..bccc934 100644 --- a/ensysmod/api/endpoints/authentication.py +++ b/ensysmod/api/endpoints/authentication.py @@ -30,7 +30,8 @@ def login( return schemas.Token(access_token=token, token_type="bearer") -@router.post("/register", response_model=schemas.User) +@router.post("/register", response_model=schemas.User, + responses={409: {"description": "User with same name already exists."}}) def register( request: schemas.UserCreate, db: Session = Depends(deps.get_db) @@ -40,7 +41,7 @@ def register( """ user = crud.user.get_by_username(db, username=request.username) if user: - raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="User with that username already exists!") user = crud.user.create(db, obj_in=request) diff --git a/ensysmod/api/endpoints/datasets.py b/ensysmod/api/endpoints/datasets.py index bba9823..356e0fc 100644 --- a/ensysmod/api/endpoints/datasets.py +++ b/ensysmod/api/endpoints/datasets.py @@ -31,7 +31,8 @@ def get_dataset(dataset_id: int, return crud.dataset.get(db, dataset_id) -@router.post("/", response_model=schemas.Dataset) +@router.post("/", response_model=schemas.Dataset, + responses={409: {"description": "Dataset with same name already exists."}}) def create_dataset(request: schemas.DatasetCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): @@ -69,4 +70,5 @@ def remove_dataset(dataset_id: int, Delete a dataset. """ # TODO Check if user has permission for dataset + # TODO remove all components, commodities, regions, etc. return crud.dataset.remove(db=db, id=dataset_id) diff --git a/ensysmod/api/endpoints/energy_commodities.py b/ensysmod/api/endpoints/energy_commodities.py index fc43712..6285a8f 100644 --- a/ensysmod/api/endpoints/energy_commodities.py +++ b/ensysmod/api/endpoints/energy_commodities.py @@ -35,7 +35,8 @@ def get_commodity(commodity_id: int, return crud.energy_commodity.get(db, commodity_id) -@router.post("/", response_model=schemas.EnergyCommodity) +@router.post("/", response_model=schemas.EnergyCommodity, + responses={409: {"description": "EnergyCommodity with same name already exists."}}) def create_commodity(request: schemas.EnergyCommodityCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/ensysmod/api/endpoints/energy_conversions.py b/ensysmod/api/endpoints/energy_conversions.py index cb62571..6ff0f4d 100644 --- a/ensysmod/api/endpoints/energy_conversions.py +++ b/ensysmod/api/endpoints/energy_conversions.py @@ -21,7 +21,8 @@ def all_energy_conversions(db: Session = Depends(deps.get_db), return crud.energy_conversion.get_multi(db, skip, limit) -@router.post("/", response_model=schemas.EnergyConversion) +@router.post("/", response_model=schemas.EnergyConversion, + responses={409: {"description": "EnergyConversion with same name already exists."}}) def create_conversion(request: schemas.EnergyConversionCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/ensysmod/api/endpoints/energy_sinks.py b/ensysmod/api/endpoints/energy_sinks.py index 95ad8bf..d46fe3c 100644 --- a/ensysmod/api/endpoints/energy_sinks.py +++ b/ensysmod/api/endpoints/energy_sinks.py @@ -21,7 +21,8 @@ def all_energy_sinks(db: Session = Depends(deps.get_db), return crud.energy_sink.get_multi(db, skip, limit) -@router.post("/", response_model=schemas.EnergySink) +@router.post("/", response_model=schemas.EnergySink, + responses={409: {"description": "EnergySink with same name already exists."}}) def create_sink(request: schemas.EnergySinkCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/ensysmod/api/endpoints/energy_sources.py b/ensysmod/api/endpoints/energy_sources.py index 2fc5521..1ec96a8 100644 --- a/ensysmod/api/endpoints/energy_sources.py +++ b/ensysmod/api/endpoints/energy_sources.py @@ -21,7 +21,8 @@ def all_energy_sources(db: Session = Depends(deps.get_db), return crud.energy_source.get_multi(db, skip, limit) -@router.post("/", response_model=schemas.EnergySource) +@router.post("/", response_model=schemas.EnergySource, + responses={409: {"description": "EnergySource with same name already exists."}}) def create_source(request: schemas.EnergySourceCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/ensysmod/api/endpoints/energy_storages.py b/ensysmod/api/endpoints/energy_storages.py index be786f7..c240abd 100644 --- a/ensysmod/api/endpoints/energy_storages.py +++ b/ensysmod/api/endpoints/energy_storages.py @@ -21,7 +21,8 @@ def all_energy_storages(db: Session = Depends(deps.get_db), return crud.energy_storage.get_multi(db, skip, limit) -@router.post("/", response_model=schemas.EnergyStorage) +@router.post("/", response_model=schemas.EnergyStorage, + responses={409: {"description": "EnergyStorage with same name already exists."}}) def create_storage(request: schemas.EnergyStorageCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/ensysmod/api/endpoints/energy_transmissions.py b/ensysmod/api/endpoints/energy_transmissions.py index 101471b..332a6ab 100644 --- a/ensysmod/api/endpoints/energy_transmissions.py +++ b/ensysmod/api/endpoints/energy_transmissions.py @@ -21,7 +21,8 @@ def all_energy_transmissions(db: Session = Depends(deps.get_db), return crud.energy_transmission.get_multi(db, skip, limit) -@router.post("/", response_model=schemas.EnergyTransmission) +@router.post("/", response_model=schemas.EnergyTransmission, + responses={409: {"description": "EnergyTransmission with same name already exists."}}) def create_transmission(request: schemas.EnergyTransmissionCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/ensysmod/api/endpoints/regions.py b/ensysmod/api/endpoints/regions.py index 8bb641a..aac8ad3 100644 --- a/ensysmod/api/endpoints/regions.py +++ b/ensysmod/api/endpoints/regions.py @@ -35,7 +35,8 @@ def get_region(region_id: int, return crud.region.get(db, region_id) -@router.post("/", response_model=schemas.Region) +@router.post("/", response_model=schemas.Region, + responses={409: {"description": "Region with same name already exists."}}) def create_region(request: schemas.RegionCreate, db: Session = Depends(deps.get_db), current: model.User = Depends(deps.get_current_user)): diff --git a/tests/api/test_authentication.py b/tests/api/test_authentication.py index 117b512..54a374e 100644 --- a/tests/api/test_authentication.py +++ b/tests/api/test_authentication.py @@ -30,7 +30,7 @@ def test_register_twice_endpoint(client: TestClient): assert new_user['username'] == payload['username'] r2 = client.post("/auth/register", json=payload) - assert r2.status_code == status.HTTP_400_BAD_REQUEST + assert r2.status_code == status.HTTP_409_CONFLICT def test_login_endpoint(client: TestClient, db: Session): From 26b2f90d6889b553ff45d933484247d31fdeac85 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Wed, 8 Dec 2021 22:07:11 +0100 Subject: [PATCH 13/22] Added time series models, schemas and endpoints Added time series capacity max Added time series operation rate max Added time series operation rate fix --- ensysmod/api/api.py | 7 +- ensysmod/api/endpoints/ts_capacity_max.py | 111 ++++++++++++++++++ .../api/endpoints/ts_operation_rate_fix.py | 111 ++++++++++++++++++ .../api/endpoints/ts_operation_rate_max.py | 111 ++++++++++++++++++ ensysmod/crud/__init__.py | 6 +- ensysmod/crud/ts_capacity.py | 32 ----- ensysmod/crud/ts_capacity_max.py | 27 +++++ ensysmod/crud/ts_consumption.py | 37 ------ ensysmod/crud/ts_generation.py | 34 ------ ensysmod/crud/ts_operation_rate_fix.py | 28 +++++ ensysmod/crud/ts_operation_rate_max.py | 28 +++++ .../{ts_base_class.py => ref_base_class.py} | 20 ++-- ensysmod/model/__init__.py | 6 +- ensysmod/model/ts_capacity.py | 8 -- ensysmod/model/ts_capacity_max.py | 8 ++ ensysmod/model/ts_consumption.py | 8 -- ensysmod/model/ts_generation.py | 8 -- ensysmod/model/ts_operation_rate_fix.py | 8 ++ ensysmod/model/ts_operation_rate_max.py | 8 ++ ensysmod/schemas/__init__.py | 6 +- ensysmod/schemas/base_ref_component_region.py | 37 ++++++ ensysmod/schemas/ts_capacity.py | 43 ------- ensysmod/schemas/ts_capacity_max.py | 35 ++++++ ensysmod/schemas/ts_consumption.py | 44 ------- ensysmod/schemas/ts_generation.py | 43 ------- ensysmod/schemas/ts_operation_rate_fix.py | 35 ++++++ ensysmod/schemas/ts_operation_rate_max.py | 35 ++++++ tests/api/test_regions.py | 23 +--- tests/api/test_ts_capacity_max.py | 34 ++++++ tests/api/test_ts_operation_rate_fix.py | 34 ++++++ tests/api/test_ts_operation_rate_max.py | 34 ++++++ tests/database/test_tables.py | 12 +- tests/utils/data_generator/__init__.py | 8 ++ tests/utils/data_generator/datasets.py | 44 +++++++ .../data_generator/energy_commodities.py | 51 ++++++++ .../data_generator/energy_conversions.py | 59 ++++++++++ tests/utils/data_generator/energy_sinks.py | 45 +++++++ tests/utils/data_generator/energy_sources.py | 45 +++++++ tests/utils/data_generator/energy_storages.py | 45 +++++++ .../data_generator/energy_transmissions.py | 45 +++++++ tests/utils/data_generator/regions.py | 32 +++++ tests/utils/utils.py | 6 +- 42 files changed, 1101 insertions(+), 300 deletions(-) create mode 100644 ensysmod/api/endpoints/ts_capacity_max.py create mode 100644 ensysmod/api/endpoints/ts_operation_rate_fix.py create mode 100644 ensysmod/api/endpoints/ts_operation_rate_max.py delete mode 100644 ensysmod/crud/ts_capacity.py create mode 100644 ensysmod/crud/ts_capacity_max.py delete mode 100644 ensysmod/crud/ts_consumption.py delete mode 100644 ensysmod/crud/ts_generation.py create mode 100644 ensysmod/crud/ts_operation_rate_fix.py create mode 100644 ensysmod/crud/ts_operation_rate_max.py rename ensysmod/database/{ts_base_class.py => ref_base_class.py} (57%) delete mode 100644 ensysmod/model/ts_capacity.py create mode 100644 ensysmod/model/ts_capacity_max.py delete mode 100644 ensysmod/model/ts_consumption.py delete mode 100644 ensysmod/model/ts_generation.py create mode 100644 ensysmod/model/ts_operation_rate_fix.py create mode 100644 ensysmod/model/ts_operation_rate_max.py create mode 100644 ensysmod/schemas/base_ref_component_region.py delete mode 100644 ensysmod/schemas/ts_capacity.py create mode 100644 ensysmod/schemas/ts_capacity_max.py delete mode 100644 ensysmod/schemas/ts_consumption.py delete mode 100644 ensysmod/schemas/ts_generation.py create mode 100644 ensysmod/schemas/ts_operation_rate_fix.py create mode 100644 ensysmod/schemas/ts_operation_rate_max.py create mode 100644 tests/api/test_ts_capacity_max.py create mode 100644 tests/api/test_ts_operation_rate_fix.py create mode 100644 tests/api/test_ts_operation_rate_max.py create mode 100644 tests/utils/data_generator/__init__.py create mode 100644 tests/utils/data_generator/datasets.py create mode 100644 tests/utils/data_generator/energy_commodities.py create mode 100644 tests/utils/data_generator/energy_conversions.py create mode 100644 tests/utils/data_generator/energy_sinks.py create mode 100644 tests/utils/data_generator/energy_sources.py create mode 100644 tests/utils/data_generator/energy_storages.py create mode 100644 tests/utils/data_generator/energy_transmissions.py create mode 100644 tests/utils/data_generator/regions.py diff --git a/ensysmod/api/api.py b/ensysmod/api/api.py index 283e93d..cd3b27c 100644 --- a/ensysmod/api/api.py +++ b/ensysmod/api/api.py @@ -1,7 +1,8 @@ from fastapi import APIRouter from .endpoints import users, authentication, energy_sources, datasets, energy_commodities, energy_sinks, \ - energy_storages, energy_transmissions, energy_conversions, regions + energy_storages, energy_transmissions, energy_conversions, regions, ts_capacity_max, ts_operation_rate_fix, \ + ts_operation_rate_max api_router = APIRouter() api_router.include_router(authentication.router, prefix="/auth", tags=["Authentication"]) @@ -14,3 +15,7 @@ api_router.include_router(energy_sources.router, prefix="/sources", tags=["Energy Sources"]) api_router.include_router(energy_storages.router, prefix="/storages", tags=["Energy Storages"]) api_router.include_router(energy_transmissions.router, prefix="/transmissions", tags=["Energy Transmissions"]) + +api_router.include_router(ts_capacity_max.router, prefix="/max-capacities", tags=["TS Capacities Max"]) +api_router.include_router(ts_operation_rate_fix.router, prefix="/fix-operation-rates", tags=["TS Operation Rates Fix"]) +api_router.include_router(ts_operation_rate_max.router, prefix="/max-operation-rates", tags=["TS Operation Rates Max"]) diff --git a/ensysmod/api/endpoints/ts_capacity_max.py b/ensysmod/api/endpoints/ts_capacity_max.py new file mode 100644 index 0000000..dedf230 --- /dev/null +++ b/ensysmod/api/endpoints/ts_capacity_max.py @@ -0,0 +1,111 @@ +from typing import List, Optional + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps +from ensysmod.schemas import CapacityMax + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.CapacityMax]) +def all_max_capacities(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.CapacityMax]: + """ + Retrieve all max capacities. + """ + return crud.capacity_max.get_multi(db, skip=skip, limit=limit) + + +@router.get("/{ts_id}", response_model=schemas.CapacityMax) +def get_capacity_max(ts_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Retrieve a max capacity. + """ + # TODO Check if user has permission for dataset and CapacityMax + return crud.capacity_max.get(db, ts_id) + + +@router.post("/", response_model=schemas.CapacityMax) +def create_capacity_max(request: schemas.CapacityMaxCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new max capacity. + """ + component = crud.energy_component.get(db=db, id=request.ref_component) + if component is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"Component {request.ref_component} not found!") + + # TODO Check if user has permission for dataset + + region = crud.region.get(db=db, id=request.ref_region) + if region is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"Region {request.ref_region} not found!") + + if component.ref_dataset != region.ref_dataset: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Component (id {request.ref_component}, dataset {component.ref_dataset}) and " + f"region (id {request.ref_region}, dataset {region.ref_dataset}) does not belong to " + f"same dataset!") + + ts = crud.capacity_max.get_by_component_and_region(db=db, component_id=request.ref_component, + region_id=request.ref_region) + if ts is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"CapacityMax for component {component.name} (id {component.id}) and " + f"region {region.name} (id {region.id}) already exists with id {ts.id}!") + + ts_in_base: Optional[List[CapacityMax]] = crud.capacity_max.get_by_component(db=db, + component_id=request.ref_component) + if ts_in_base is not None: + # get maximum length max_capacities in ts_in_base + max_length = 0 + for ts_in in ts_in_base: + if ts_in.max_capacities is not None: + max_length = max(max_length, len(ts_in.max_capacities)) + + if max_length > 0 and max_length != len(request.max_capacities): + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail=f"CapacityMax for component {component.name} (id {component.id}) has a length " + f"of {max_length}. Your new time series has {len(request.max_capacities)} " + f"elements.") + + return crud.capacity_max.create(db=db, obj_in=request) + + +@router.put("/{ts_id}", response_model=schemas.CapacityMax) +def update_capacity_max(ts_id: int, + request: schemas.CapacityMaxUpdate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Update a max capacity. + """ + # TODO Check if user has permission for CapacityMax + ts = crud.capacity_max.get(db=db, id=ts_id) + if ts is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"CapacityMax {ts_id} not found!") + return crud.capacity_max.update(db=db, db_obj=ts, obj_in=request) + + +@router.delete("/{ts_id}", response_model=schemas.CapacityMax) +def remove_capacity_max(ts_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Delete a max capacity. + """ + ts = crud.capacity_max.get(db=db, id=ts_id) + if ts is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"CapacityMax {ts_id} not found!") + # TODO Check if user has permission for dataset + return crud.capacity_max.remove(db=db, id=ts_id) diff --git a/ensysmod/api/endpoints/ts_operation_rate_fix.py b/ensysmod/api/endpoints/ts_operation_rate_fix.py new file mode 100644 index 0000000..5390e25 --- /dev/null +++ b/ensysmod/api/endpoints/ts_operation_rate_fix.py @@ -0,0 +1,111 @@ +from typing import List, Optional + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps +from ensysmod.schemas import OperationRateFix + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.OperationRateFix]) +def all_fix_operation_rates(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.OperationRateFix]: + """ + Retrieve all fix operation rates. + """ + return crud.operation_rate_fix.get_multi(db, skip=skip, limit=limit) + + +@router.get("/{ts_id}", response_model=schemas.OperationRateFix) +def get_operation_rate_fix(ts_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Retrieve a fix operation rate. + """ + # TODO Check if user has permission for dataset and OperationRateFix + return crud.operation_rate_fix.get(db, ts_id) + + +@router.post("/", response_model=schemas.OperationRateFix) +def create_operation_rate_fix(request: schemas.OperationRateFixCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new fix operation rate. + """ + component = crud.energy_component.get(db=db, id=request.ref_component) + if component is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"Component {request.ref_component} not found!") + + # TODO Check if user has permission for dataset + + region = crud.region.get(db=db, id=request.ref_region) + if region is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"Region {request.ref_region} not found!") + + if component.ref_dataset != region.ref_dataset: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Component (id {request.ref_component}, dataset {component.ref_dataset}) and " + f"region (id {request.ref_region}, dataset {region.ref_dataset}) does not belong to " + f"same dataset!") + + ts = crud.operation_rate_fix.get_by_component_and_region(db=db, component_id=request.ref_component, + region_id=request.ref_region) + if ts is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"OperationRateFix for component {component.name} (id {component.id}) and " + f"region {region.name} (id {region.id}) already exists with id {ts.id}!") + + ts_in_base: Optional[List[OperationRateFix]] = crud.operation_rate_fix.get_by_component(db=db, + component_id=request.ref_component) + if ts_in_base is not None: + # get maximum length fix_operation_rates in ts_in_base + max_length = 0 + for ts_in in ts_in_base: + if ts_in.fix_operation_rates is not None: + max_length = max(max_length, len(ts_in.fix_operation_rates)) + + if max_length > 0 and max_length != len(request.fix_operation_rates): + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail=f"OperationRateFix for component {component.name} (id {component.id}) has a " + f"length of {max_length}. Your new time series has " + f"{len(request.fix_operation_rates)} elements.") + + return crud.operation_rate_fix.create(db=db, obj_in=request) + + +@router.put("/{ts_id}", response_model=schemas.OperationRateFix) +def update_operation_rate_fix(ts_id: int, + request: schemas.OperationRateFixUpdate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Update a fix operation rate. + """ + # TODO Check if user has permission for OperationRateFix + ts = crud.operation_rate_fix.get(db=db, id=ts_id) + if ts is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"OperationRateFix {ts_id} not found!") + return crud.operation_rate_fix.update(db=db, db_obj=ts, obj_in=request) + + +@router.delete("/{ts_id}", response_model=schemas.OperationRateFix) +def remove_operation_rate_fix(ts_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Delete a fix operation rate. + """ + ts = crud.operation_rate_fix.get(db=db, id=ts_id) + if ts is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"OperationRateFix {ts_id} not found!") + # TODO Check if user has permission for dataset + return crud.operation_rate_fix.remove(db=db, id=ts_id) diff --git a/ensysmod/api/endpoints/ts_operation_rate_max.py b/ensysmod/api/endpoints/ts_operation_rate_max.py new file mode 100644 index 0000000..e159ab4 --- /dev/null +++ b/ensysmod/api/endpoints/ts_operation_rate_max.py @@ -0,0 +1,111 @@ +from typing import List, Optional + +from fastapi import APIRouter, Depends, HTTPException, status +from sqlalchemy.orm import Session + +from ensysmod import schemas, model, crud +from ensysmod.api import deps +from ensysmod.schemas import OperationRateMax + +router = APIRouter() + + +@router.get("/", response_model=List[schemas.OperationRateMax]) +def all_max_operation_rates(db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user), + skip: int = 0, + limit: int = 100) -> List[schemas.OperationRateMax]: + """ + Retrieve all max operation rates. + """ + return crud.operation_rate_max.get_multi(db, skip=skip, limit=limit) + + +@router.get("/{ts_id}", response_model=schemas.OperationRateMax) +def get_operation_rate_max(ts_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Retrieve a max operation rate. + """ + # TODO Check if user has permission for dataset and OperationRateMax + return crud.operation_rate_max.get(db, ts_id) + + +@router.post("/", response_model=schemas.OperationRateMax) +def create_operation_rate_max(request: schemas.OperationRateMaxCreate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Create a new max operation rate. + """ + component = crud.energy_component.get(db=db, id=request.ref_component) + if component is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"Component {request.ref_component} not found!") + + # TODO Check if user has permission for dataset + + region = crud.region.get(db=db, id=request.ref_region) + if region is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, + detail=f"Region {request.ref_region} not found!") + + if component.ref_dataset != region.ref_dataset: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail=f"Component (id {request.ref_component}, dataset {component.ref_dataset}) and " + f"region (id {request.ref_region}, dataset {region.ref_dataset}) does not belong to " + f"same dataset!") + + ts = crud.operation_rate_max.get_by_component_and_region(db=db, component_id=request.ref_component, + region_id=request.ref_region) + if ts is not None: + raise HTTPException(status_code=status.HTTP_409_CONFLICT, + detail=f"OperationRateMax for component {component.name} (id {component.id}) and " + f"region {region.name} (id {region.id}) already exists with id {ts.id}!") + + ts_in_base: Optional[List[OperationRateMax]] = crud.operation_rate_max.get_by_component(db=db, + component_id=request.ref_component) + if ts_in_base is not None: + # get maximum length max_operation_rates in ts_in_base + max_length = 0 + for ts_in in ts_in_base: + if ts_in.max_operation_rates is not None: + max_length = max(max_length, len(ts_in.max_operation_rates)) + + if max_length > 0 and max_length != len(request.max_operation_rates): + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, + detail=f"OperationRateMax for component {component.name} (id {component.id}) has a " + f"length of {max_length}. Your new time series has " + f"{len(request.max_operation_rates)} elements.") + + return crud.operation_rate_max.create(db=db, obj_in=request) + + +@router.put("/{ts_id}", response_model=schemas.OperationRateMax) +def update_operation_rate_max(ts_id: int, + request: schemas.OperationRateMaxUpdate, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Update a max operation rate. + """ + # TODO Check if user has permission for OperationRateMax + ts = crud.operation_rate_max.get(db=db, id=ts_id) + if ts is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"OperationRateMax {ts_id} not found!") + return crud.operation_rate_max.update(db=db, db_obj=ts, obj_in=request) + + +@router.delete("/{ts_id}", response_model=schemas.OperationRateMax) +def remove_operation_rate_max(ts_id: int, + db: Session = Depends(deps.get_db), + current: model.User = Depends(deps.get_current_user)): + """ + Delete a max operation rate. + """ + ts = crud.operation_rate_max.get(db=db, id=ts_id) + if ts is None: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"OperationRateMax {ts_id} not found!") + # TODO Check if user has permission for dataset + return crud.operation_rate_max.remove(db=db, id=ts_id) diff --git a/ensysmod/crud/__init__.py b/ensysmod/crud/__init__.py index 6367599..52c7a32 100644 --- a/ensysmod/crud/__init__.py +++ b/ensysmod/crud/__init__.py @@ -10,7 +10,7 @@ from .energy_storage import energy_storage from .energy_transmission import energy_transmission from .region import region -from .ts_capacity import capacity -from .ts_consumption import consumption -from .ts_generation import generation +from .ts_capacity_max import capacity_max +from .ts_operation_rate_max import operation_rate_max +from .ts_operation_rate_fix import operation_rate_fix from .user import user diff --git a/ensysmod/crud/ts_capacity.py b/ensysmod/crud/ts_capacity.py deleted file mode 100644 index c436cf0..0000000 --- a/ensysmod/crud/ts_capacity.py +++ /dev/null @@ -1,32 +0,0 @@ -from sqlalchemy.orm import Session - -from ensysmod import crud -from ensysmod.crud.base import CRUDBase -from ensysmod.model import Capacity -from ensysmod.schemas import CapacityCreate, CapacityUpdate - - -# noinspection PyMethodMayBeStatic,PyArgumentList -class CRUDCapacity(CRUDBase[Capacity, CapacityCreate, CapacityUpdate]): - def create(self, db: Session, *, obj_in: CapacityCreate) -> Capacity: - region_obj = crud.region.get_by_name(obj_in.region) - if not region_obj: - raise ValueError(f"Region '{obj_in.region}' does not exist.") - - source_obj = crud.energy_source.get_by_name(obj_in.source) - if not source_obj: - raise ValueError(f"Energy source '{obj_in.source}' does not exist.") - - db_obj = Capacity( - year=obj_in.year, - quantity=obj_in.quantity, - region=region_obj.id, - source=source_obj.id, - ) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - -capacity = CRUDCapacity(Capacity) diff --git a/ensysmod/crud/ts_capacity_max.py b/ensysmod/crud/ts_capacity_max.py new file mode 100644 index 0000000..2fc439f --- /dev/null +++ b/ensysmod/crud/ts_capacity_max.py @@ -0,0 +1,27 @@ +from typing import Optional, List + +from sqlalchemy.orm import Session + +from ensysmod.crud.base import CRUDBase +from ensysmod.model import CapacityMax +from ensysmod.schemas import CapacityMaxCreate, CapacityMaxUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDCapacityMax(CRUDBase[CapacityMax, CapacityMaxCreate, CapacityMaxUpdate]): + """ + CRUD operations for CapacityMax + """ + + def get_by_component(self, db: Session, *, component_id: int) -> Optional[List[CapacityMax]]: + return db.query(CapacityMax) \ + .filter(CapacityMax.ref_component == component_id) \ + .all() + + def get_by_component_and_region(self, db: Session, *, component_id: int, region_id: int) -> Optional[CapacityMax]: + return db.query(CapacityMax) \ + .filter(CapacityMax.ref_component == component_id and CapacityMax.ref_region == region_id) \ + .first() + + +capacity_max = CRUDCapacityMax(CapacityMax) diff --git a/ensysmod/crud/ts_consumption.py b/ensysmod/crud/ts_consumption.py deleted file mode 100644 index 5580992..0000000 --- a/ensysmod/crud/ts_consumption.py +++ /dev/null @@ -1,37 +0,0 @@ -from sqlalchemy.orm import Session - -from ensysmod import crud -from ensysmod.crud.base import CRUDBase -from ensysmod.model import Consumption -from ensysmod.schemas import ConsumptionCreate, ConsumptionUpdate - - -# noinspection PyMethodMayBeStatic,PyArgumentList -class CRUDConsumption(CRUDBase[Consumption, ConsumptionCreate, ConsumptionUpdate]): - def create(self, db: Session, *, obj_in: ConsumptionCreate) -> Consumption: - region_obj = crud.region.get_by_name(obj_in.region) - if not region_obj: - raise ValueError(f"Region '{obj_in.region}' does not exist.") - - source_obj = crud.energy_source.get_by_name(obj_in.source) - if not source_obj: - raise ValueError(f"Energy source '{obj_in.source}' does not exist.") - - sink_obj = crud.energy_sink.get_by_name(obj_in.sink) - if not sink_obj: - raise ValueError(f"Energy sink '{obj_in.sink}' does not exist.") - - db_obj = Consumption( - year=obj_in.year, - quantity=obj_in.quantity, - region=region_obj.id, - source=source_obj.id, - sink=sink_obj.id, - ) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - -consumption = CRUDConsumption(Consumption) diff --git a/ensysmod/crud/ts_generation.py b/ensysmod/crud/ts_generation.py deleted file mode 100644 index 751915b..0000000 --- a/ensysmod/crud/ts_generation.py +++ /dev/null @@ -1,34 +0,0 @@ -from sqlalchemy.orm import Session - -from ensysmod import crud -from ensysmod.crud.base import CRUDBase -from ensysmod.model import Generation -from ensysmod.schemas import GenerationCreate, GenerationUpdate - - -# noinspection PyMethodMayBeStatic,PyArgumentList -class CRUDGeneration(CRUDBase[Generation, GenerationCreate, GenerationUpdate]): - def create(self, db: Session, *, obj_in: GenerationCreate) -> Generation: - region_obj = crud.region.get_by_name(obj_in.region) - if not region_obj: - raise ValueError(f"Region '{obj_in.region}' does not exist.") - - source_obj = crud.energy_source.get_by_name(obj_in.source) - if not source_obj: - raise ValueError(f"Energy source '{obj_in.source}' does not exist.") - - db_obj = Generation( - year=obj_in.year, - quantity=obj_in.quantity, - region=region_obj.id, - source=source_obj.id, - ) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj - - pass - - -generation = CRUDGeneration(Generation) diff --git a/ensysmod/crud/ts_operation_rate_fix.py b/ensysmod/crud/ts_operation_rate_fix.py new file mode 100644 index 0000000..e023215 --- /dev/null +++ b/ensysmod/crud/ts_operation_rate_fix.py @@ -0,0 +1,28 @@ +from typing import Optional, List + +from sqlalchemy.orm import Session + +from ensysmod.crud.base import CRUDBase +from ensysmod.model import OperationRateFix +from ensysmod.schemas import OperationRateFixCreate, OperationRateFixUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDOperationRateFix(CRUDBase[OperationRateFix, OperationRateFixCreate, OperationRateFixUpdate]): + """ + CRUD operations for OperationRateFix + """ + + def get_by_component(self, db: Session, *, component_id: int) -> Optional[List[OperationRateFix]]: + return db.query(OperationRateFix) \ + .filter(OperationRateFix.ref_component == component_id) \ + .all() + + def get_by_component_and_region(self, db: Session, *, component_id: int, region_id: int) \ + -> Optional[OperationRateFix]: + return db.query(OperationRateFix) \ + .filter(OperationRateFix.ref_component == component_id and OperationRateFix.ref_region == region_id) \ + .first() + + +operation_rate_fix = CRUDOperationRateFix(OperationRateFix) diff --git a/ensysmod/crud/ts_operation_rate_max.py b/ensysmod/crud/ts_operation_rate_max.py new file mode 100644 index 0000000..c4f18c5 --- /dev/null +++ b/ensysmod/crud/ts_operation_rate_max.py @@ -0,0 +1,28 @@ +from typing import Optional, List + +from sqlalchemy.orm import Session + +from ensysmod.crud.base import CRUDBase +from ensysmod.model import OperationRateMax +from ensysmod.schemas import OperationRateMaxCreate, OperationRateMaxUpdate + + +# noinspection PyMethodMayBeStatic,PyArgumentList +class CRUDOperationRateMax(CRUDBase[OperationRateMax, OperationRateMaxCreate, OperationRateMaxUpdate]): + """ + CRUD operations for OperationRateMax + """ + + def get_by_component(self, db: Session, *, component_id: int) -> Optional[List[OperationRateMax]]: + return db.query(OperationRateMax) \ + .filter(OperationRateMax.ref_component == component_id) \ + .all() + + def get_by_component_and_region(self, db: Session, *, component_id: int, region_id: int) \ + -> Optional[OperationRateMax]: + return db.query(OperationRateMax) \ + .filter(OperationRateMax.ref_component == component_id and OperationRateMax.ref_region == region_id) \ + .first() + + +operation_rate_max = CRUDOperationRateMax(OperationRateMax) diff --git a/ensysmod/database/ts_base_class.py b/ensysmod/database/ref_base_class.py similarity index 57% rename from ensysmod/database/ts_base_class.py rename to ensysmod/database/ref_base_class.py index a60db1f..7160520 100644 --- a/ensysmod/database/ts_base_class.py +++ b/ensysmod/database/ref_base_class.py @@ -1,25 +1,29 @@ -from sqlalchemy import Column, Integer, DateTime -from sqlalchemy.orm import declared_attr +from sqlalchemy import Column, Integer +from sqlalchemy.orm import declared_attr, relationship from sqlalchemy.sql.schema import ForeignKey -class TimeSeriesBase: +class RefCRBase: """ - Base class for all time series classes. + Base class for tables referencing components and regions. """ @declared_attr def id(self): return Column(Integer, primary_key=True) + @declared_attr + def ref_component(self): + return Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + @declared_attr def ref_region(self): return Column(Integer, ForeignKey("region.id"), index=True, nullable=False) @declared_attr - def ref_component(self): - return Column(Integer, ForeignKey("energy_component.id"), index=True, nullable=False) + def component(self): + return relationship("EnergyComponent") @declared_attr - def datetime(self): - return Column(DateTime, nullable=False) + def region(self): + return relationship("Region") diff --git a/ensysmod/model/__init__.py b/ensysmod/model/__init__.py index 02cef04..cabd671 100644 --- a/ensysmod/model/__init__.py +++ b/ensysmod/model/__init__.py @@ -11,7 +11,7 @@ from .energy_storage import EnergyStorage from .energy_transmission import EnergyTransmission from .region import Region -from .ts_capacity import Capacity -from .ts_consumption import Consumption -from .ts_generation import Generation +from .ts_capacity_max import CapacityMax +from .ts_operation_rate_fix import OperationRateFix +from .ts_operation_rate_max import OperationRateMax from .user import User diff --git a/ensysmod/model/ts_capacity.py b/ensysmod/model/ts_capacity.py deleted file mode 100644 index 1ffa2e3..0000000 --- a/ensysmod/model/ts_capacity.py +++ /dev/null @@ -1,8 +0,0 @@ -from sqlalchemy import Column, DECIMAL - -from ensysmod.database.base_class import Base -from ensysmod.database.ts_base_class import TimeSeriesBase - - -class Capacity(TimeSeriesBase, Base): - quantity = Column(DECIMAL, nullable=False) diff --git a/ensysmod/model/ts_capacity_max.py b/ensysmod/model/ts_capacity_max.py new file mode 100644 index 0000000..470fe23 --- /dev/null +++ b/ensysmod/model/ts_capacity_max.py @@ -0,0 +1,8 @@ +from sqlalchemy import Column, PickleType + +from ensysmod.database.base_class import Base +from ensysmod.database.ref_base_class import RefCRBase + + +class CapacityMax(RefCRBase, Base): + max_capacities = Column(PickleType, nullable=False) diff --git a/ensysmod/model/ts_consumption.py b/ensysmod/model/ts_consumption.py deleted file mode 100644 index 9baf6f0..0000000 --- a/ensysmod/model/ts_consumption.py +++ /dev/null @@ -1,8 +0,0 @@ -from sqlalchemy import Column, DECIMAL - -from ensysmod.database.base_class import Base -from ensysmod.database.ts_base_class import TimeSeriesBase - - -class Consumption(TimeSeriesBase, Base): - quantity = Column(DECIMAL, nullable=False) diff --git a/ensysmod/model/ts_generation.py b/ensysmod/model/ts_generation.py deleted file mode 100644 index cf85ac3..0000000 --- a/ensysmod/model/ts_generation.py +++ /dev/null @@ -1,8 +0,0 @@ -from sqlalchemy import Column, DECIMAL - -from ensysmod.database.base_class import Base -from ensysmod.database.ts_base_class import TimeSeriesBase - - -class Generation(TimeSeriesBase, Base): - quantity = Column(DECIMAL, nullable=False) diff --git a/ensysmod/model/ts_operation_rate_fix.py b/ensysmod/model/ts_operation_rate_fix.py new file mode 100644 index 0000000..114422a --- /dev/null +++ b/ensysmod/model/ts_operation_rate_fix.py @@ -0,0 +1,8 @@ +from sqlalchemy import Column, PickleType + +from ensysmod.database.base_class import Base +from ensysmod.database.ref_base_class import RefCRBase + + +class OperationRateFix(RefCRBase, Base): + fix_operation_rates = Column(PickleType, nullable=False) diff --git a/ensysmod/model/ts_operation_rate_max.py b/ensysmod/model/ts_operation_rate_max.py new file mode 100644 index 0000000..4211639 --- /dev/null +++ b/ensysmod/model/ts_operation_rate_max.py @@ -0,0 +1,8 @@ +from sqlalchemy import Column, PickleType + +from ensysmod.database.base_class import Base +from ensysmod.database.ref_base_class import RefCRBase + + +class OperationRateMax(RefCRBase, Base): + max_operation_rates = Column(PickleType, nullable=False) diff --git a/ensysmod/schemas/__init__.py b/ensysmod/schemas/__init__.py index 80b0a37..7ea93e1 100644 --- a/ensysmod/schemas/__init__.py +++ b/ensysmod/schemas/__init__.py @@ -11,7 +11,7 @@ from .energy_transmission import EnergyTransmission, EnergyTransmissionCreate, EnergyTransmissionUpdate from .region import Region, RegionCreate, RegionUpdate from .token import Token, TokenPayload -from .ts_capacity import Capacity, CapacityCreate, CapacityUpdate, CapacityInDB -from .ts_consumption import Consumption, ConsumptionCreate, ConsumptionUpdate, ConsumptionInDB -from .ts_generation import Generation, GenerationCreate, GenerationUpdate, GenerationInDB +from .ts_capacity_max import CapacityMax, CapacityMaxCreate, CapacityMaxUpdate +from .ts_operation_rate_fix import OperationRateFix, OperationRateFixCreate, OperationRateFixUpdate +from .ts_operation_rate_max import OperationRateMax, OperationRateMaxCreate, OperationRateMaxUpdate from .user import User, UserCreate, UserInDB, UserUpdate diff --git a/ensysmod/schemas/base_ref_component_region.py b/ensysmod/schemas/base_ref_component_region.py new file mode 100644 index 0000000..a424281 --- /dev/null +++ b/ensysmod/schemas/base_ref_component_region.py @@ -0,0 +1,37 @@ +from pydantic import BaseModel + +from ensysmod.schemas import EnergyComponent, Region + + +class RefCRBaseBase(BaseModel): + """ + Shared properties for a referenced component region model. Used as a base class for all schemas. + """ + pass + + +class RefCRBaseCreate(RefCRBaseBase): + """ + Properties to receive via API on creation of a referenced component region model. + """ + ref_component: int + ref_region: int + + +class RefCRBaseUpdate(RefCRBaseBase): + """ + Properties to receive via API on update of a referenced component region model. + """ + pass + + +class RefCRBase(RefCRBaseBase): + """ + Properties to return via API for a referenced component region model. + """ + id: int + component: EnergyComponent + region: Region + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/ts_capacity.py b/ensysmod/schemas/ts_capacity.py deleted file mode 100644 index a10c679..0000000 --- a/ensysmod/schemas/ts_capacity.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel - - -# Shared properties -class CapacityBase(BaseModel): - year: Optional[str] = None - quantity: Optional[str] = None - - -# Properties to receive via API on creation -class CapacityCreate(CapacityBase): - year: int - quantity: int - region: str - source: str - - -# Properties to receive via API on update -class CapacityUpdate(CapacityBase): - year: Optional[int] = None - quantity: Optional[int] = None - region: Optional[str] = None - source: Optional[str] = None - - -class CapacityInDBBase(CapacityBase): - id: Optional[int] = None - - class Config: - orm_mode = True - - -# Additional properties to return via API -class Capacity(CapacityInDBBase): - pass - - -# Additional properties stored in DB -class CapacityInDB(CapacityInDBBase): - region: Optional[int] = None - source: Optional[int] = None diff --git a/ensysmod/schemas/ts_capacity_max.py b/ensysmod/schemas/ts_capacity_max.py new file mode 100644 index 0000000..7205308 --- /dev/null +++ b/ensysmod/schemas/ts_capacity_max.py @@ -0,0 +1,35 @@ +from typing import List + +from pydantic import BaseModel + +from ensysmod.schemas.base_ref_component_region import RefCRBaseBase, RefCRBaseCreate, RefCRBaseUpdate, RefCRBase + + +class CapacityMaxBase(RefCRBaseBase, BaseModel): + """ + Shared properties for a max capacity. Used as a base class for all schemas. + """ + max_capacities: List[float] + + +class CapacityMaxCreate(CapacityMaxBase, RefCRBaseCreate): + """ + Properties to receive via API on creation of a max capacity. + """ + pass + + +class CapacityMaxUpdate(CapacityMaxBase, RefCRBaseUpdate): + """ + Properties to receive via API on update of a max capacity. + """ + pass + + +class CapacityMax(CapacityMaxBase, RefCRBase): + """ + Properties to return via API for a max capacity. + """ + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/ts_consumption.py b/ensysmod/schemas/ts_consumption.py deleted file mode 100644 index c57c382..0000000 --- a/ensysmod/schemas/ts_consumption.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel - - -# Shared properties -class ConsumptionBase(BaseModel): - year: Optional[int] = None - quantity: Optional[int] = None - - -# Properties to receive via API on creation -class ConsumptionCreate(ConsumptionBase): - year: int - quantity: int - region: str - source: str - sink: str - - -# Properties to receive via API on update -class ConsumptionUpdate(ConsumptionBase): - region: Optional[str] = None - source: Optional[str] = None - sink: Optional[str] = None - - -class ConsumptionInDBBase(ConsumptionBase): - id: Optional[int] = None - - class Config: - orm_mode = True - - -# Additional properties to return via API -class Consumption(ConsumptionInDBBase): - pass - - -# Additional properties stored in DB -class ConsumptionInDB(ConsumptionInDBBase): - region: Optional[int] = None - source: Optional[int] = None - sink: Optional[int] = None diff --git a/ensysmod/schemas/ts_generation.py b/ensysmod/schemas/ts_generation.py deleted file mode 100644 index 5e8e78d..0000000 --- a/ensysmod/schemas/ts_generation.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel - - -# Shared properties -class GenerationBase(BaseModel): - year: Optional[int] = None - quantity: Optional[int] = None - - -# Properties to receive via API on creation -class GenerationCreate(GenerationBase): - year: int - quantity: int - region: str - source: str - - -# Properties to receive via API on update -class GenerationUpdate(GenerationBase): - year: Optional[int] = None - quantity: Optional[int] = None - region: Optional[str] = None - source: Optional[str] = None - - -class GenerationInDBBase(GenerationBase): - id: Optional[int] = None - - class Config: - orm_mode = True - - -# Additional properties to return via API -class Generation(GenerationInDBBase): - pass - - -# Additional properties stored in DB -class GenerationInDB(GenerationInDBBase): - region: str - source: str diff --git a/ensysmod/schemas/ts_operation_rate_fix.py b/ensysmod/schemas/ts_operation_rate_fix.py new file mode 100644 index 0000000..bbb6335 --- /dev/null +++ b/ensysmod/schemas/ts_operation_rate_fix.py @@ -0,0 +1,35 @@ +from typing import List + +from pydantic import BaseModel + +from ensysmod.schemas.base_ref_component_region import RefCRBaseBase, RefCRBaseCreate, RefCRBaseUpdate, RefCRBase + + +class OperationRateFixBase(RefCRBaseBase, BaseModel): + """ + Shared properties for a fix operation rate. Used as a base class for all schemas. + """ + fix_operation_rates: List[float] + + +class OperationRateFixCreate(OperationRateFixBase, RefCRBaseCreate): + """ + Properties to receive via API on creation of a fix operation rate. + """ + pass + + +class OperationRateFixUpdate(OperationRateFixBase, RefCRBaseUpdate): + """ + Properties to receive via API on update of a fix operation rate. + """ + pass + + +class OperationRateFix(OperationRateFixBase, RefCRBase): + """ + Properties to return via API for a fix operation rate. + """ + + class Config: + orm_mode = True diff --git a/ensysmod/schemas/ts_operation_rate_max.py b/ensysmod/schemas/ts_operation_rate_max.py new file mode 100644 index 0000000..38d4f9c --- /dev/null +++ b/ensysmod/schemas/ts_operation_rate_max.py @@ -0,0 +1,35 @@ +from typing import List + +from pydantic import BaseModel + +from ensysmod.schemas.base_ref_component_region import RefCRBaseBase, RefCRBaseCreate, RefCRBaseUpdate, RefCRBase + + +class OperationRateMaxBase(RefCRBaseBase, BaseModel): + """ + Shared properties for a max operation rate. Used as a base class for all schemas. + """ + max_operation_rates: List[float] + + +class OperationRateMaxCreate(OperationRateMaxBase, RefCRBaseCreate): + """ + Properties to receive via API on creation of a max operation rate. + """ + pass + + +class OperationRateMaxUpdate(OperationRateMaxBase, RefCRBaseUpdate): + """ + Properties to receive via API on update of a max operation rate. + """ + pass + + +class OperationRateMax(OperationRateMaxBase, RefCRBase): + """ + Properties to return via API for a max operation rate. + """ + + class Config: + orm_mode = True diff --git a/tests/api/test_regions.py b/tests/api/test_regions.py index 0e8a0c0..83173d2 100644 --- a/tests/api/test_regions.py +++ b/tests/api/test_regions.py @@ -5,28 +5,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud -from ensysmod.schemas import RegionCreate, Region -from tests.api.test_datasets import get_random_existing_dataset -from tests.utils.utils import random_lower_string - - -def get_random_region_create(db: Session) -> RegionCreate: - dataset = get_random_existing_dataset(db) - return RegionCreate(name=f"Region-{dataset.id}-" + random_lower_string(), - ref_dataset=dataset.id) - - -def get_random_existing_region(db: Session) -> Region: - create_request = get_random_region_create(db) - return crud.region.create(db=db, obj_in=create_request) +from ensysmod.schemas import RegionCreate +from tests.utils import data_generator as data_gen def test_create_region(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a region. """ - create_request = get_random_region_create(db) + create_request = data_gen.random_region_create(db) response = client.post("/regions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -39,7 +26,7 @@ def test_create_existing_region(client: TestClient, normal_user_headers: Dict[st """ Test creating a existing region. """ - existing_region = get_random_existing_region(db) + existing_region = data_gen.random_existing_region(db) create_request = RegionCreate(**jsonable_encoder(existing_region)) response = client.post("/regions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT @@ -49,7 +36,7 @@ def test_create_region_unknown_dataset(client: TestClient, normal_user_headers: """ Test creating a region. """ - create_request = get_random_region_create(db) + create_request = data_gen.random_region_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/regions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_ts_capacity_max.py b/tests/api/test_ts_capacity_max.py new file mode 100644 index 0000000..7c9604f --- /dev/null +++ b/tests/api/test_ts_capacity_max.py @@ -0,0 +1,34 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod.schemas import CapacityMaxCreate +from tests.utils import data_generator as data_gen +from tests.utils.utils import random_float_numbers + + +def get_random_max_capacity_create(db: Session) -> CapacityMaxCreate: + source = data_gen.fixed_existing_energy_sink(db) + region = data_gen.fixed_existing_region(db) + return CapacityMaxCreate( + ref_component=source.component.id, + ref_region=region.id, + max_capacities=random_float_numbers() + ) + + +def test_create_max_capacity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a max capacity time series. + """ + create_request = get_random_max_capacity_create(db) + response = client.post("/max-capacities/", headers=normal_user_headers, data=create_request.json()) + print(response.text) + assert response.status_code == status.HTTP_200_OK + + created_ts = response.json() + assert created_ts["component"]["id"] == create_request.ref_component + assert created_ts["region"]["id"] == create_request.ref_region + assert created_ts["max_capacities"] == create_request.max_capacities diff --git a/tests/api/test_ts_operation_rate_fix.py b/tests/api/test_ts_operation_rate_fix.py new file mode 100644 index 0000000..8f90e08 --- /dev/null +++ b/tests/api/test_ts_operation_rate_fix.py @@ -0,0 +1,34 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod.schemas import OperationRateFixCreate +from tests.utils.utils import random_float_numbers +from tests.utils import data_generator as data_gen + + +def get_random_fix_operation_rate_create(db: Session) -> OperationRateFixCreate: + source = data_gen.fixed_existing_energy_sink(db) + region = data_gen.fixed_existing_region(db) + return OperationRateFixCreate( + ref_component=source.component.id, + ref_region=region.id, + fix_operation_rates=random_float_numbers() + ) + + +def test_create_fix_operation_rate(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a fix operation rate time series. + """ + create_request = get_random_fix_operation_rate_create(db) + response = client.post("/fix-operation-rates/", headers=normal_user_headers, data=create_request.json()) + print(response.text) + assert response.status_code == status.HTTP_200_OK + + created_ts = response.json() + assert created_ts["component"]["id"] == create_request.ref_component + assert created_ts["region"]["id"] == create_request.ref_region + assert created_ts["fix_operation_rates"] == create_request.fix_operation_rates diff --git a/tests/api/test_ts_operation_rate_max.py b/tests/api/test_ts_operation_rate_max.py new file mode 100644 index 0000000..04c5069 --- /dev/null +++ b/tests/api/test_ts_operation_rate_max.py @@ -0,0 +1,34 @@ +from typing import Dict + +from fastapi import status +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session + +from ensysmod.schemas import OperationRateMaxCreate +from tests.utils import data_generator as data_gen +from tests.utils.utils import random_float_numbers + + +def get_random_max_operation_rate_create(db: Session) -> OperationRateMaxCreate: + source = data_gen.fixed_existing_energy_sink(db) + region = data_gen.fixed_existing_region(db) + return OperationRateMaxCreate( + ref_component=source.component.id, + ref_region=region.id, + max_operation_rates=random_float_numbers() + ) + + +def test_create_max_operation_rate(client: TestClient, normal_user_headers: Dict[str, str], db: Session): + """ + Test creating a max operation rate time series. + """ + create_request = get_random_max_operation_rate_create(db) + response = client.post("/max-operation-rates/", headers=normal_user_headers, data=create_request.json()) + print(response.text) + assert response.status_code == status.HTTP_200_OK + + created_ts = response.json() + assert created_ts["component"]["id"] == create_request.ref_component + assert created_ts["region"]["id"] == create_request.ref_region + assert created_ts["max_operation_rates"] == create_request.max_operation_rates diff --git a/tests/database/test_tables.py b/tests/database/test_tables.py index a497e2f..d529d6c 100644 --- a/tests/database/test_tables.py +++ b/tests/database/test_tables.py @@ -34,16 +34,16 @@ def test_table_energy_transmission(db: Session): assert check_table_exists(db.bind.raw_connection().cursor(), 'energy_transmission') -def test_table_capacity(db: Session): - assert check_table_exists(db.bind.raw_connection().cursor(), 'capacity') +def test_table_capacity_max(db: Session): + assert check_table_exists(db.bind.raw_connection().cursor(), 'capacity_max') -def test_table_consumption(db: Session): - assert check_table_exists(db.bind.raw_connection().cursor(), 'consumption') +def test_table_operation_rate_fix(db: Session): + assert check_table_exists(db.bind.raw_connection().cursor(), 'operation_rate_fix') -def test_table_generation(db: Session): - assert check_table_exists(db.bind.raw_connection().cursor(), 'generation') +def test_table_operation_rate_max(db: Session): + assert check_table_exists(db.bind.raw_connection().cursor(), 'operation_rate_max') def test_table_region(db: Session): diff --git a/tests/utils/data_generator/__init__.py b/tests/utils/data_generator/__init__.py new file mode 100644 index 0000000..07d9250 --- /dev/null +++ b/tests/utils/data_generator/__init__.py @@ -0,0 +1,8 @@ +from .datasets import * +from .energy_commodities import * +from .energy_conversions import * +from .energy_sinks import * +from .energy_sources import * +from .energy_storages import * +from .energy_transmissions import * +from .regions import * diff --git a/tests/utils/data_generator/datasets.py b/tests/utils/data_generator/datasets.py new file mode 100644 index 0000000..b930ba7 --- /dev/null +++ b/tests/utils/data_generator/datasets.py @@ -0,0 +1,44 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import Dataset +from ensysmod.schemas import DatasetCreate +from tests.utils.utils import random_lower_string + + +def random_dataset_create() -> DatasetCreate: + """ + Generates a random dataset create request. + """ + dataset_name = "DS " + random_lower_string() + dataset_description = "DS desc " + random_lower_string() + return DatasetCreate(name=dataset_name, description=dataset_description) + + +def random_existing_dataset(db: Session) -> Dataset: + """ + Generates a random existing dataset. + """ + create_request = random_dataset_create() + return crud.dataset.create(db=db, obj_in=create_request) + + +def fixed_dataset_create() -> DatasetCreate: + """ + Generates a fixed dataset create request. + Will always return the same create request. + """ + return DatasetCreate(name="Fixed dataset", description="Fixed dataset description") + + +def fixed_existing_dataset(db: Session) -> Dataset: + """ + Generates a fixed existing dataset. + Will always return the same dataset. + """ + create_request = fixed_dataset_create() + dataset = crud.dataset.get_by_name(db=db, name=create_request.name) + if dataset is None: + dataset = crud.dataset.create(db=db, obj_in=create_request) + return dataset + diff --git a/tests/utils/data_generator/energy_commodities.py b/tests/utils/data_generator/energy_commodities.py new file mode 100644 index 0000000..754cd48 --- /dev/null +++ b/tests/utils/data_generator/energy_commodities.py @@ -0,0 +1,51 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyCommodity +from ensysmod.schemas import EnergyCommodityCreate +from tests.utils.data_generator.datasets import fixed_existing_dataset, random_existing_dataset +from tests.utils.utils import random_lower_string + + +def random_energy_commodity_create(db: Session) -> EnergyCommodityCreate: + """ + Generate a random energy commodity create request. + """ + dataset = random_existing_dataset(db) + return EnergyCommodityCreate(name=f"EnergyCommodity-{dataset.id}-" + random_lower_string(), + ref_dataset=dataset.id, + description="EnergyCommodity description", + unit="kWh") + + +def random_existing_energy_commodity(db: Session) -> EnergyCommodity: + """ + Generate a random existing energy commodity. + """ + create_request = random_energy_commodity_create(db) + return crud.energy_commodity.create(db=db, obj_in=create_request) + + +def fixed_energy_commodity_create(db: Session) -> EnergyCommodityCreate: + """ + Generate a fixed energy commodity create request. + Will always return the same energy commodity. + """ + dataset = fixed_existing_dataset(db) + return EnergyCommodityCreate(name=f"EnergyCommodity-{dataset.id}-Fixed", + ref_dataset=dataset.id, + description="EnergyCommodity description", + unit="kWh") + + +def fixed_existing_energy_commodity(db: Session) -> EnergyCommodity: + """ + Generate a fixed existing energy commodity. + Will always return the same energy commodity. + """ + create_request = fixed_energy_commodity_create(db) + commodity = crud.energy_commodity.get_by_dataset_and_name(db=db, dataset_id=create_request.ref_dataset, + name=create_request.name) + if commodity is None: + return crud.energy_commodity.create(db=db, obj_in=create_request) + return commodity diff --git a/tests/utils/data_generator/energy_conversions.py b/tests/utils/data_generator/energy_conversions.py new file mode 100644 index 0000000..f2ba772 --- /dev/null +++ b/tests/utils/data_generator/energy_conversions.py @@ -0,0 +1,59 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyConversion +from ensysmod.schemas import EnergyConversionCreate +from tests.utils.data_generator.datasets import random_existing_dataset, fixed_existing_dataset +from tests.utils.data_generator.energy_commodities import random_existing_energy_commodity, \ + fixed_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def random_energy_conversion_create(db: Session) -> EnergyConversionCreate: + """ + Generate a random EnergyConversionCreate object. + """ + dataset = random_existing_dataset(db) + commodity = random_existing_energy_commodity(db) + return EnergyConversionCreate( + ref_dataset=dataset.id, + name=f"EnergyConversion-{dataset.id}-{random_lower_string()}", + description="Description", + commodity_unit=commodity.name, + ) + + +def random_existing_energy_conversion(db: Session) -> EnergyConversion: + """ + Generate a random EnergyConversion object. + """ + create_request = random_energy_conversion_create(db) + return crud.energy_conversion.create(db=db, obj_in=create_request) + + +def fixed_energy_conversion_create(db: Session) -> EnergyConversionCreate: + """ + Generate a fixed EnergyConversionCreate object. + Will always return the same object. + """ + dataset = fixed_existing_dataset(db) + commodity = fixed_existing_energy_commodity(db) + return EnergyConversionCreate( + ref_dataset=dataset.id, + name=f"EnergyConversion-{dataset.id}-Fixed", + description="Description", + commodity_unit=commodity.name, + ) + + +def fixed_existing_energy_conversion(db: Session) -> EnergyConversion: + """ + Generate a fixed EnergyConversion object. + Will always return the same object. + """ + create_request = fixed_energy_conversion_create(db) + conversion = crud.energy_conversion.get_by_dataset_and_name(db, dataset_id=create_request.ref_dataset, + name=create_request.name) + if conversion is None: + conversion = crud.energy_conversion.create(db=db, obj_in=create_request) + return conversion diff --git a/tests/utils/data_generator/energy_sinks.py b/tests/utils/data_generator/energy_sinks.py new file mode 100644 index 0000000..f2440f9 --- /dev/null +++ b/tests/utils/data_generator/energy_sinks.py @@ -0,0 +1,45 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergySink +from ensysmod.schemas import EnergySinkCreate +from tests.utils.data_generator.datasets import random_existing_dataset, fixed_existing_dataset +from tests.utils.data_generator.energy_commodities import random_existing_energy_commodity, \ + fixed_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def random_energy_sink_create(db: Session) -> EnergySinkCreate: + dataset = random_existing_dataset(db) + commodity = random_existing_energy_commodity(db) + return EnergySinkCreate( + ref_dataset=dataset.id, + name=f"EnergySink-{dataset.id}-{random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def random_existing_energy_sink(db: Session) -> EnergySink: + create_request = random_energy_sink_create(db) + return crud.energy_sink.create(db=db, obj_in=create_request) + + +def fixed_energy_sink_create(db: Session) -> EnergySinkCreate: + dataset = fixed_existing_dataset(db) + commodity = fixed_existing_energy_commodity(db) + return EnergySinkCreate( + ref_dataset=dataset.id, + name=f"EnergySink-{dataset.id}-Fixed", + description="Description", + commodity=commodity.name, + ) + + +def fixed_existing_energy_sink(db: Session) -> EnergySink: + create_request = fixed_energy_sink_create(db) + sink = crud.energy_sink.get_by_dataset_and_name(db=db, dataset_id=create_request.ref_dataset, + name=create_request.name) + if sink is None: + sink = crud.energy_sink.create(db=db, obj_in=create_request) + return sink diff --git a/tests/utils/data_generator/energy_sources.py b/tests/utils/data_generator/energy_sources.py new file mode 100644 index 0000000..84f870e --- /dev/null +++ b/tests/utils/data_generator/energy_sources.py @@ -0,0 +1,45 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergySource +from ensysmod.schemas import EnergySourceCreate +from tests.utils.data_generator import fixed_existing_dataset, fixed_existing_energy_commodity +from tests.utils.data_generator.datasets import random_existing_dataset +from tests.utils.data_generator.energy_commodities import random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def random_energy_source_create(db: Session) -> EnergySourceCreate: + dataset = random_existing_dataset(db) + commodity = random_existing_energy_commodity(db) + return EnergySourceCreate( + ref_dataset=dataset.id, + name=f"EnergySource-{dataset.id}-{random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def random_existing_energy_source(db: Session) -> EnergySource: + create_request = random_energy_source_create(db) + return crud.energy_source.create(db=db, obj_in=create_request) + + +def fixed_energy_source_create(db: Session) -> EnergySourceCreate: + dataset = fixed_existing_dataset(db) + commodity = fixed_existing_energy_commodity(db) + return EnergySourceCreate( + ref_dataset=dataset.id, + name=f"EnergySource-{dataset.id}-Fixed", + description="Description", + commodity=commodity.name, + ) + + +def fixed_existing_energy_source(db: Session) -> EnergySource: + create_request = fixed_energy_source_create(db) + source = crud.energy_source.get_by_dataset_and_name(db=db, dataset_id=create_request.ref_dataset, + name=create_request.name) + if source is None: + source = crud.energy_source.create(db=db, obj_in=create_request) + return source diff --git a/tests/utils/data_generator/energy_storages.py b/tests/utils/data_generator/energy_storages.py new file mode 100644 index 0000000..42213c9 --- /dev/null +++ b/tests/utils/data_generator/energy_storages.py @@ -0,0 +1,45 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyStorage +from ensysmod.schemas import EnergyStorageCreate +from tests.utils.data_generator import fixed_existing_dataset, fixed_existing_energy_commodity +from tests.utils.data_generator.datasets import random_existing_dataset +from tests.utils.data_generator.energy_commodities import random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def random_energy_storage_create(db: Session) -> EnergyStorageCreate: + dataset = random_existing_dataset(db) + commodity = random_existing_energy_commodity(db) + return EnergyStorageCreate( + ref_dataset=dataset.id, + name=f"EnergyStorage-{dataset.id}-{random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def random_existing_energy_storage(db: Session) -> EnergyStorage: + create_request = random_energy_storage_create(db) + return crud.energy_storage.create(db=db, obj_in=create_request) + + +def fixed_energy_storage_create(db: Session) -> EnergyStorageCreate: + dataset = fixed_existing_dataset(db) + commodity = fixed_existing_energy_commodity(db) + return EnergyStorageCreate( + ref_dataset=dataset.id, + name=f"EnergyStorage-{dataset.id}-Fixed", + description="Description", + commodity=commodity.name, + ) + + +def fixed_existing_energy_storage(db: Session) -> EnergyStorage: + create_request = fixed_energy_storage_create(db) + storage = crud.energy_storage.get_by_dataset_and_name(db=db, dataset_id=create_request.ref_dataset, + name=create_request.name) + if storage is None: + storage = crud.energy_storage.create(db=db, obj_in=create_request) + return storage diff --git a/tests/utils/data_generator/energy_transmissions.py b/tests/utils/data_generator/energy_transmissions.py new file mode 100644 index 0000000..37c073c --- /dev/null +++ b/tests/utils/data_generator/energy_transmissions.py @@ -0,0 +1,45 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import EnergyTransmission +from ensysmod.schemas import EnergyTransmissionCreate +from tests.utils.data_generator import fixed_existing_dataset, fixed_existing_energy_commodity +from tests.utils.data_generator.datasets import random_existing_dataset +from tests.utils.data_generator.energy_commodities import random_existing_energy_commodity +from tests.utils.utils import random_lower_string + + +def random_energy_transmission_create(db: Session) -> EnergyTransmissionCreate: + dataset = random_existing_dataset(db) + commodity = random_existing_energy_commodity(db) + return EnergyTransmissionCreate( + ref_dataset=dataset.id, + name=f"EnergyTransmission-{dataset.id}-{random_lower_string()}", + description="Description", + commodity=commodity.name, + ) + + +def random_existing_energy_transmission(db: Session) -> EnergyTransmission: + create_request = random_energy_transmission_create(db) + return crud.energy_transmission.create(db=db, obj_in=create_request) + + +def fixed_energy_transmission_create(db: Session) -> EnergyTransmissionCreate: + dataset = fixed_existing_dataset(db) + commodity = fixed_existing_energy_commodity(db) + return EnergyTransmissionCreate( + ref_dataset=dataset.id, + name=f"EnergyTransmission-{dataset.id}-Fixed", + description="Description", + commodity=commodity.name, + ) + + +def fixed_existing_energy_transmission(db: Session) -> EnergyTransmission: + create_request = fixed_energy_transmission_create(db) + transmission = crud.energy_transmission.get_by_dataset_and_name(db=db, dataset_id=create_request.ref_dataset, + name=create_request.name) + if transmission is None: + transmission = crud.energy_transmission.create(db=db, obj_in=create_request) + return transmission diff --git a/tests/utils/data_generator/regions.py b/tests/utils/data_generator/regions.py new file mode 100644 index 0000000..4d9666b --- /dev/null +++ b/tests/utils/data_generator/regions.py @@ -0,0 +1,32 @@ +from sqlalchemy.orm import Session + +from ensysmod import crud +from ensysmod.model import Region +from ensysmod.schemas import RegionCreate +from tests.utils.data_generator import random_existing_dataset, fixed_existing_dataset +from tests.utils.utils import random_lower_string + + +def random_region_create(db: Session) -> RegionCreate: + dataset = random_existing_dataset(db) + return RegionCreate(name=f"Region-{dataset.id}-{random_lower_string()}", + ref_dataset=dataset.id) + + +def random_existing_region(db: Session) -> Region: + create_request = random_region_create(db) + return crud.region.create(db=db, obj_in=create_request) + + +def fixed_region_create(db: Session) -> RegionCreate: + dataset = fixed_existing_dataset(db) + return RegionCreate(name=f"Region-{dataset.id}-Fixed", + ref_dataset=dataset.id) + + +def fixed_existing_region(db: Session) -> Region: + create_request = fixed_region_create(db) + region = crud.region.get_by_dataset_and_name(db=db, dataset_id=create_request.ref_dataset, name=create_request.name) + if region is None: + region = crud.region.create(db=db, obj_in=create_request) + return region diff --git a/tests/utils/utils.py b/tests/utils/utils.py index 5ba547b..2e3759d 100644 --- a/tests/utils/utils.py +++ b/tests/utils/utils.py @@ -1,6 +1,6 @@ import random import string -from typing import Dict +from typing import Dict, List from fastapi.testclient import TestClient from sqlalchemy.orm import Session @@ -14,6 +14,10 @@ def random_lower_string() -> str: return "".join(random.choices(string.ascii_lowercase, k=32)) +def random_float_numbers(size: int = 10) -> List[float]: + return [random.uniform(0, 1) for _ in range(size)] + + def user_authentication_headers( *, client: TestClient, username: str, password: str ) -> Dict[str, str]: From db32b7d354be66c23595f17caec73516801dfbd8 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Wed, 8 Dec 2021 22:10:24 +0100 Subject: [PATCH 14/22] Fixed linting errors --- tests/utils/data_generator/__init__.py | 20 ++++++++++++-------- tests/utils/data_generator/datasets.py | 1 - 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/utils/data_generator/__init__.py b/tests/utils/data_generator/__init__.py index 07d9250..dcdf445 100644 --- a/tests/utils/data_generator/__init__.py +++ b/tests/utils/data_generator/__init__.py @@ -1,8 +1,12 @@ -from .datasets import * -from .energy_commodities import * -from .energy_conversions import * -from .energy_sinks import * -from .energy_sources import * -from .energy_storages import * -from .energy_transmissions import * -from .regions import * +from .datasets import random_existing_dataset, random_dataset_create, fixed_existing_dataset +from .energy_commodities import random_existing_energy_commodity, fixed_existing_energy_commodity, \ + random_energy_commodity_create +from .energy_conversions import random_existing_energy_commodity, fixed_existing_energy_commodity, \ + random_energy_conversion_create +from .energy_sinks import random_existing_energy_sink, fixed_existing_energy_sink, random_energy_sink_create +from .energy_sources import random_existing_energy_source, fixed_existing_energy_source, random_energy_source_create +from .energy_storages import random_existing_energy_storage, fixed_existing_energy_storage, \ + random_energy_storage_create +from .energy_transmissions import random_existing_energy_transmission, fixed_existing_energy_transmission, \ + random_energy_transmission_create +from .regions import random_existing_region, fixed_existing_region, random_region_create diff --git a/tests/utils/data_generator/datasets.py b/tests/utils/data_generator/datasets.py index b930ba7..c024a2b 100644 --- a/tests/utils/data_generator/datasets.py +++ b/tests/utils/data_generator/datasets.py @@ -41,4 +41,3 @@ def fixed_existing_dataset(db: Session) -> Dataset: if dataset is None: dataset = crud.dataset.create(db=db, obj_in=create_request) return dataset - From 0073264c3a4c774b0bfc897ad6778c2ad9eb578a Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Wed, 8 Dec 2021 22:29:30 +0100 Subject: [PATCH 15/22] Fixed import issue in __init__.py --- tests/utils/data_generator/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/data_generator/__init__.py b/tests/utils/data_generator/__init__.py index dcdf445..b75d04d 100644 --- a/tests/utils/data_generator/__init__.py +++ b/tests/utils/data_generator/__init__.py @@ -1,7 +1,7 @@ from .datasets import random_existing_dataset, random_dataset_create, fixed_existing_dataset from .energy_commodities import random_existing_energy_commodity, fixed_existing_energy_commodity, \ random_energy_commodity_create -from .energy_conversions import random_existing_energy_commodity, fixed_existing_energy_commodity, \ +from .energy_conversions import random_existing_energy_conversion, fixed_existing_energy_conversion, \ random_energy_conversion_create from .energy_sinks import random_existing_energy_sink, fixed_existing_energy_sink, random_energy_sink_create from .energy_sources import random_existing_energy_source, fixed_existing_energy_source, random_energy_source_create From 7b6c5c66e2f66bd5621a75170a34b59452dd5ed7 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Wed, 8 Dec 2021 22:35:54 +0100 Subject: [PATCH 16/22] Removed unnecessary test case --- tests/crud/test_energy_conversion.py | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 tests/crud/test_energy_conversion.py diff --git a/tests/crud/test_energy_conversion.py b/tests/crud/test_energy_conversion.py deleted file mode 100644 index 99dc21a..0000000 --- a/tests/crud/test_energy_conversion.py +++ /dev/null @@ -1,13 +0,0 @@ -import pytest -from sqlalchemy.orm import Session - -from ensysmod import crud -from ensysmod.schemas import EnergyConversionCreate - - -@pytest.mark.skip(reason="Not working while reworking the models.") -def test_create_energy_conversion(db: Session): - create = EnergyConversionCreate(name="test_energy_conversion", description="test_energy_conversion desc") - energy_conversion = crud.energy_conversion.create(db, obj_in=create) - assert energy_conversion.name == "test_energy_conversion" - assert energy_conversion.description == "test_energy_conversion desc" From 101a1ea8d7dbc3ee58255fb8f1dee021bad3bfae Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 9 Dec 2021 09:42:19 +0100 Subject: [PATCH 17/22] Changed create request generators for test cases --- tests/api/test_datasets.py | 23 ++++++-------------- tests/api/test_energy_commodities.py | 25 +++++---------------- tests/api/test_energy_conversions.py | 30 +++++--------------------- tests/api/test_energy_sinks.py | 30 +++++--------------------- tests/api/test_energy_sources.py | 30 +++++--------------------- tests/api/test_energy_storages.py | 30 +++++--------------------- tests/api/test_energy_transmissions.py | 30 +++++--------------------- 7 files changed, 36 insertions(+), 162 deletions(-) diff --git a/tests/api/test_datasets.py b/tests/api/test_datasets.py index 176f1ff..335cbf8 100644 --- a/tests/api/test_datasets.py +++ b/tests/api/test_datasets.py @@ -5,28 +5,17 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud -from ensysmod.schemas import DatasetCreate, DatasetUpdate, Dataset +from ensysmod.schemas import DatasetCreate, DatasetUpdate +from tests.utils import data_generator as data_gen from tests.utils.utils import random_lower_string -def get_random_dataset_create() -> DatasetCreate: - dataset_name = "DS " + random_lower_string() - dataset_description = "DS desc " + random_lower_string() - return DatasetCreate(name=dataset_name, description=dataset_description) - - -def get_random_existing_dataset(db: Session) -> Dataset: - create_request = get_random_dataset_create() - return crud.dataset.create(db=db, obj_in=create_request) - - def test_create_dataset(client: TestClient, normal_user_headers: Dict[str, str]): """ Test creating a dataset. """ # Create a dataset - create_request = get_random_dataset_create() + create_request = data_gen.random_dataset_create() response = client.post( "/datasets/", @@ -44,7 +33,7 @@ def test_create_existing_dataset(db: Session, client: TestClient, normal_user_he """ Test creating an existing dataset. """ - existing_dataset = get_random_existing_dataset(db) + existing_dataset = data_gen.random_existing_dataset(db) create_request = DatasetCreate(**jsonable_encoder(existing_dataset)) response = client.post( "/datasets/", @@ -58,7 +47,7 @@ def test_update_existing_dataset(db: Session, client: TestClient, normal_user_he """ Test updating an existing dataset. """ - existing_dataset = get_random_existing_dataset(db) + existing_dataset = data_gen.random_existing_dataset(db) update_request = DatasetUpdate(**jsonable_encoder(existing_dataset)) new_description = random_lower_string() update_request.description = new_description @@ -78,7 +67,7 @@ def test_delete_existing_dataset(db: Session, client: TestClient, normal_user_he """ Test deleting an existing dataset. """ - existing_dataset = get_random_existing_dataset(db) + existing_dataset = data_gen.random_existing_dataset(db) response = client.delete( f"/datasets/{existing_dataset.id}", headers=normal_user_headers diff --git a/tests/api/test_energy_commodities.py b/tests/api/test_energy_commodities.py index b783bd6..4aee8e6 100644 --- a/tests/api/test_energy_commodities.py +++ b/tests/api/test_energy_commodities.py @@ -5,30 +5,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud -from ensysmod.schemas import EnergyCommodityCreate, EnergyCommodity -from tests.api.test_datasets import get_random_existing_dataset -from tests.utils.utils import random_lower_string - - -def get_random_energy_commodity_create(db: Session) -> EnergyCommodityCreate: - dataset = get_random_existing_dataset(db) - return EnergyCommodityCreate(name=f"EnergyCommodity-{dataset.id}-" + random_lower_string(), - ref_dataset=dataset.id, - description="EnergyCommodity description", - unit="kWh") - - -def get_random_existing_energy_commodity(db: Session) -> EnergyCommodity: - create_request = get_random_energy_commodity_create(db) - return crud.energy_commodity.create(db=db, obj_in=create_request) +from ensysmod.schemas import EnergyCommodityCreate +from tests.utils import data_generator as data_gen def test_create_energy_commodity(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy commodity. """ - create_request = get_random_energy_commodity_create(db) + create_request = data_gen.random_energy_commodity_create(db) response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -43,7 +28,7 @@ def test_create_existing_energy_commodity(client: TestClient, normal_user_header """ Test creating a existing energy commodity. """ - existing_commodity = get_random_existing_energy_commodity(db) + existing_commodity = data_gen.random_existing_energy_commodity(db) create_request = EnergyCommodityCreate(**jsonable_encoder(existing_commodity)) response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_409_CONFLICT @@ -53,7 +38,7 @@ def test_create_energy_commodity_unknown_dataset(client: TestClient, normal_user """ Test creating a energy commodity. """ - create_request = get_random_energy_commodity_create(db) + create_request = data_gen.random_energy_commodity_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/commodities/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_conversions.py b/tests/api/test_energy_conversions.py index 62b4410..31846f9 100644 --- a/tests/api/test_energy_conversions.py +++ b/tests/api/test_energy_conversions.py @@ -4,35 +4,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud from ensysmod.model import EnergyComponentType -from ensysmod.schemas import EnergyConversionCreate, EnergyConversion -from tests.api.test_datasets import get_random_existing_dataset -from tests.api.test_energy_commodities import get_random_existing_energy_commodity -from tests.utils.utils import random_lower_string - - -def get_random_energy_conversion_create(db: Session) -> EnergyConversionCreate: - dataset = get_random_existing_dataset(db) - commodity = get_random_existing_energy_commodity(db) - return EnergyConversionCreate( - ref_dataset=dataset.id, - name=f"Energy Conversion {random_lower_string()}", - description="Description", - commodity_unit=commodity.name, - ) - - -def get_random_existing_energy_conversion(db: Session) -> EnergyConversion: - create_request = get_random_energy_conversion_create(db) - return crud.energy_conversion.create(db=db, obj_in=create_request) +from tests.utils import data_generator as data_gen def test_create_energy_conversion(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy conversion. """ - create_request = get_random_energy_conversion_create(db) + create_request = data_gen.random_energy_conversion_create(db) response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -47,7 +27,7 @@ def test_create_existing_energy_conversion(client: TestClient, normal_user_heade """ Test creating a existing energy conversion. """ - create_request = get_random_energy_conversion_create(db) + create_request = data_gen.random_energy_conversion_create(db) response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) @@ -58,7 +38,7 @@ def test_create_energy_conversion_unknown_dataset(client: TestClient, normal_use """ Test creating a energy conversion. """ - create_request = get_random_energy_conversion_create(db) + create_request = data_gen.random_energy_conversion_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -69,7 +49,7 @@ def test_create_energy_conversion_unknown_commodity(client: TestClient, normal_u """ Test creating a energy conversion. """ - create_request = get_random_energy_conversion_create(db) + create_request = data_gen.random_energy_conversion_create(db) create_request.commodity_unit = "0" # ungültige Anfrage response = client.post("/conversions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_sinks.py b/tests/api/test_energy_sinks.py index 73cfb60..a455a29 100644 --- a/tests/api/test_energy_sinks.py +++ b/tests/api/test_energy_sinks.py @@ -4,35 +4,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud from ensysmod.model import EnergyComponentType -from ensysmod.schemas import EnergySinkCreate, EnergySink -from tests.api.test_datasets import get_random_existing_dataset -from tests.api.test_energy_commodities import get_random_existing_energy_commodity -from tests.utils.utils import random_lower_string - - -def get_random_energy_sink_create(db: Session) -> EnergySinkCreate: - dataset = get_random_existing_dataset(db) - commodity = get_random_existing_energy_commodity(db) - return EnergySinkCreate( - ref_dataset=dataset.id, - name=f"Energy Sink {random_lower_string()}", - description="Description", - commodity=commodity.name, - ) - - -def get_random_existing_energy_sink(db: Session) -> EnergySink: - create_request = get_random_energy_sink_create(db) - return crud.energy_sink.create(db=db, obj_in=create_request) +from tests.utils import data_generator as data_gen def test_create_energy_sink(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy sink. """ - create_request = get_random_energy_sink_create(db) + create_request = data_gen.random_energy_sink_create(db) response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -47,7 +27,7 @@ def test_create_existing_energy_sink(client: TestClient, normal_user_headers: Di """ Test creating a existing energy sink. """ - create_request = get_random_energy_sink_create(db) + create_request = data_gen.random_energy_sink_create(db) response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) @@ -58,7 +38,7 @@ def test_create_energy_sink_unknown_dataset(client: TestClient, normal_user_head """ Test creating a energy sink. """ - create_request = get_random_energy_sink_create(db) + create_request = data_gen.random_energy_sink_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -68,7 +48,7 @@ def test_create_energy_sink_unknown_commodity(client: TestClient, normal_user_he """ Test creating a energy sink. """ - create_request = get_random_energy_sink_create(db) + create_request = data_gen.random_energy_sink_create(db) create_request.commodity = "0" # ungültige Anfrage response = client.post("/sinks/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_sources.py b/tests/api/test_energy_sources.py index e49197b..0715840 100644 --- a/tests/api/test_energy_sources.py +++ b/tests/api/test_energy_sources.py @@ -4,35 +4,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud from ensysmod.model import EnergyComponentType -from ensysmod.schemas import EnergySourceCreate, EnergySource -from tests.api.test_datasets import get_random_existing_dataset -from tests.api.test_energy_commodities import get_random_existing_energy_commodity -from tests.utils.utils import random_lower_string - - -def get_random_energy_source_create(db: Session) -> EnergySourceCreate: - dataset = get_random_existing_dataset(db) - commodity = get_random_existing_energy_commodity(db) - return EnergySourceCreate( - ref_dataset=dataset.id, - name=f"Energy Source {random_lower_string()}", - description="Description", - commodity=commodity.name, - ) - - -def get_random_existing_energy_source(db: Session) -> EnergySource: - create_request = get_random_energy_source_create(db) - return crud.energy_source.create(db=db, obj_in=create_request) +from tests.utils import data_generator as data_gen def test_create_energy_source(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy source. """ - create_request = get_random_energy_source_create(db) + create_request = data_gen.random_energy_source_create(db) response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -47,7 +27,7 @@ def test_create_existing_energy_source(client: TestClient, normal_user_headers: """ Test creating a existing energy source. """ - create_request = get_random_energy_source_create(db) + create_request = data_gen.random_energy_source_create(db) response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) @@ -58,7 +38,7 @@ def test_create_energy_source_unknown_dataset(client: TestClient, normal_user_he """ Test creating a energy source. """ - create_request = get_random_energy_source_create(db) + create_request = data_gen.random_energy_source_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -68,7 +48,7 @@ def test_create_energy_source_unknown_commodity(client: TestClient, normal_user_ """ Test creating a energy source. """ - create_request = get_random_energy_source_create(db) + create_request = data_gen.random_energy_source_create(db) create_request.commodity = "0" # ungültige Anfrage response = client.post("/sources/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_storages.py b/tests/api/test_energy_storages.py index 8b36801..57489f4 100644 --- a/tests/api/test_energy_storages.py +++ b/tests/api/test_energy_storages.py @@ -4,35 +4,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud from ensysmod.model import EnergyComponentType -from ensysmod.schemas import EnergyStorageCreate, EnergyStorage -from tests.api.test_datasets import get_random_existing_dataset -from tests.api.test_energy_commodities import get_random_existing_energy_commodity -from tests.utils.utils import random_lower_string - - -def get_random_energy_storage_create(db: Session) -> EnergyStorageCreate: - dataset = get_random_existing_dataset(db) - commodity = get_random_existing_energy_commodity(db) - return EnergyStorageCreate( - ref_dataset=dataset.id, - name=f"Energy Storage {random_lower_string()}", - description="Description", - commodity=commodity.name, - ) - - -def get_random_existing_energy_storage(db: Session) -> EnergyStorage: - create_request = get_random_energy_storage_create(db) - return crud.energy_storage.create(db=db, obj_in=create_request) +from tests.utils import data_generator as data_gen def test_create_energy_storage(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy storage. """ - create_request = get_random_energy_storage_create(db) + create_request = data_gen.random_energy_storage_create(db) response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -47,7 +27,7 @@ def test_create_existing_energy_storage(client: TestClient, normal_user_headers: """ Test creating a existing energy storage. """ - create_request = get_random_energy_storage_create(db) + create_request = data_gen.random_energy_storage_create(db) response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) @@ -58,7 +38,7 @@ def test_create_energy_storage_unknown_dataset(client: TestClient, normal_user_h """ Test creating a energy storage. """ - create_request = get_random_energy_storage_create(db) + create_request = data_gen.random_energy_storage_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -68,7 +48,7 @@ def test_create_energy_storage_unknown_commodity(client: TestClient, normal_user """ Test creating a energy storage. """ - create_request = get_random_energy_storage_create(db) + create_request = data_gen.random_energy_storage_create(db) create_request.commodity = "0" # ungültige Anfrage response = client.post("/storages/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND diff --git a/tests/api/test_energy_transmissions.py b/tests/api/test_energy_transmissions.py index 5438c90..c316d60 100644 --- a/tests/api/test_energy_transmissions.py +++ b/tests/api/test_energy_transmissions.py @@ -4,35 +4,15 @@ from fastapi.testclient import TestClient from sqlalchemy.orm import Session -from ensysmod import crud from ensysmod.model import EnergyComponentType -from ensysmod.schemas import EnergyTransmissionCreate, EnergyTransmission -from tests.api.test_datasets import get_random_existing_dataset -from tests.api.test_energy_commodities import get_random_existing_energy_commodity -from tests.utils.utils import random_lower_string - - -def get_random_energy_transmission_create(db: Session) -> EnergyTransmissionCreate: - dataset = get_random_existing_dataset(db) - commodity = get_random_existing_energy_commodity(db) - return EnergyTransmissionCreate( - ref_dataset=dataset.id, - name=f"Energy Transmission {random_lower_string()}", - description="Description", - commodity=commodity.name, - ) - - -def get_random_existing_energy_transmission(db: Session) -> EnergyTransmission: - create_request = get_random_energy_transmission_create(db) - return crud.energy_transmission.create(db=db, obj_in=create_request) +from tests.utils import data_generator as data_gen def test_create_energy_transmission(client: TestClient, normal_user_headers: Dict[str, str], db: Session): """ Test creating a energy transmission. """ - create_request = get_random_energy_transmission_create(db) + create_request = data_gen.random_energy_transmission_create(db) response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK @@ -47,7 +27,7 @@ def test_create_existing_energy_transmission(client: TestClient, normal_user_hea """ Test creating a existing energy transmission. """ - create_request = get_random_energy_transmission_create(db) + create_request = data_gen.random_energy_transmission_create(db) response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_200_OK response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) @@ -59,7 +39,7 @@ def test_create_energy_transmission_unknown_dataset(client: TestClient, normal_u """ Test creating a energy transmission. """ - create_request = get_random_energy_transmission_create(db) + create_request = data_gen.random_energy_transmission_create(db) create_request.ref_dataset = 0 # ungültige Anfrage response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND @@ -70,7 +50,7 @@ def test_create_energy_transmission_unknown_commodity(client: TestClient, normal """ Test creating a energy transmission. """ - create_request = get_random_energy_transmission_create(db) + create_request = data_gen.random_energy_transmission_create(db) create_request.commodity = "0" # ungültige Anfrage response = client.post("/transmissions/", headers=normal_user_headers, data=create_request.json()) assert response.status_code == status.HTTP_404_NOT_FOUND From 386042e40311981e2fa2e9d0664e3b4db0fe557b Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 9 Dec 2021 10:02:21 +0100 Subject: [PATCH 18/22] Added cost parameters to energy component schema --- ensysmod/schemas/energy_component.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ensysmod/schemas/energy_component.py b/ensysmod/schemas/energy_component.py index c2470da..0f463a0 100644 --- a/ensysmod/schemas/energy_component.py +++ b/ensysmod/schemas/energy_component.py @@ -2,7 +2,7 @@ from pydantic import BaseModel -from ensysmod.model import EnergyComponentType +from ensysmod.model import EnergyComponentType, CapacityVariableDomain class EnergyComponentBase(BaseModel): @@ -13,6 +13,15 @@ class EnergyComponentBase(BaseModel): type: EnergyComponentType description: Optional[str] = None + capacity_variable: Optional[bool] = None + capacity_variable_domain: Optional[CapacityVariableDomain] = None + capacity_per_plant_unit: Optional[float] = None + + invest_per_capacity: Optional[float] = None + opex_per_capacity: Optional[float] = None + interest_rate: Optional[float] = None + economic_lifetime: Optional[int] = None + class EnergyComponentCreate(EnergyComponentBase): """ From d340e23f02f9a6508a849494fee797844764593a Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 9 Dec 2021 10:03:06 +0100 Subject: [PATCH 19/22] Improved testing experience --- tests/api/test_energy_conversions.py | 5 ++--- tests/api/test_energy_sinks.py | 5 ++--- tests/api/test_energy_sources.py | 5 ++--- tests/api/test_energy_storages.py | 5 ++--- tests/api/test_energy_transmissions.py | 5 ++--- tests/utils/assertions.py | 10 ++++++++++ 6 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 tests/utils/assertions.py diff --git a/tests/api/test_energy_conversions.py b/tests/api/test_energy_conversions.py index 31846f9..6e31cd2 100644 --- a/tests/api/test_energy_conversions.py +++ b/tests/api/test_energy_conversions.py @@ -6,6 +6,7 @@ from ensysmod.model import EnergyComponentType from tests.utils import data_generator as data_gen +from tests.utils.assertions import assert_energy_component def test_create_energy_conversion(client: TestClient, normal_user_headers: Dict[str, str], db: Session): @@ -17,9 +18,7 @@ def test_create_energy_conversion(client: TestClient, normal_user_headers: Dict[ assert response.status_code == status.HTTP_200_OK created_conversion = response.json() - assert created_conversion["component"]["name"] == create_request.name - assert created_conversion["component"]["description"] == create_request.description - assert created_conversion["component"]["type"] == EnergyComponentType.CONVERSION.value + assert_energy_component(created_conversion["component"], create_request, EnergyComponentType.CONVERSION) assert created_conversion["commodity_unit"]["name"] == create_request.commodity_unit diff --git a/tests/api/test_energy_sinks.py b/tests/api/test_energy_sinks.py index a455a29..013cc24 100644 --- a/tests/api/test_energy_sinks.py +++ b/tests/api/test_energy_sinks.py @@ -6,6 +6,7 @@ from ensysmod.model import EnergyComponentType from tests.utils import data_generator as data_gen +from tests.utils.assertions import assert_energy_component def test_create_energy_sink(client: TestClient, normal_user_headers: Dict[str, str], db: Session): @@ -17,9 +18,7 @@ def test_create_energy_sink(client: TestClient, normal_user_headers: Dict[str, s assert response.status_code == status.HTTP_200_OK created_sinks = response.json() - assert created_sinks["component"]["name"] == create_request.name - assert created_sinks["component"]["description"] == create_request.description - assert created_sinks["component"]["type"] == EnergyComponentType.SINK.value + assert_energy_component(created_sinks["component"], create_request, EnergyComponentType.SINK) assert created_sinks["commodity"]["name"] == create_request.commodity diff --git a/tests/api/test_energy_sources.py b/tests/api/test_energy_sources.py index 0715840..293eec1 100644 --- a/tests/api/test_energy_sources.py +++ b/tests/api/test_energy_sources.py @@ -6,6 +6,7 @@ from ensysmod.model import EnergyComponentType from tests.utils import data_generator as data_gen +from tests.utils.assertions import assert_energy_component def test_create_energy_source(client: TestClient, normal_user_headers: Dict[str, str], db: Session): @@ -17,9 +18,7 @@ def test_create_energy_source(client: TestClient, normal_user_headers: Dict[str, assert response.status_code == status.HTTP_200_OK created_source = response.json() - assert created_source["component"]["name"] == create_request.name - assert created_source["component"]["description"] == create_request.description - assert created_source["component"]["type"] == EnergyComponentType.SOURCE.value + assert_energy_component(created_source["component"], create_request, EnergyComponentType.SOURCE) assert created_source["commodity"]["name"] == create_request.commodity diff --git a/tests/api/test_energy_storages.py b/tests/api/test_energy_storages.py index 57489f4..ff8dd32 100644 --- a/tests/api/test_energy_storages.py +++ b/tests/api/test_energy_storages.py @@ -6,6 +6,7 @@ from ensysmod.model import EnergyComponentType from tests.utils import data_generator as data_gen +from tests.utils.assertions import assert_energy_component def test_create_energy_storage(client: TestClient, normal_user_headers: Dict[str, str], db: Session): @@ -17,9 +18,7 @@ def test_create_energy_storage(client: TestClient, normal_user_headers: Dict[str assert response.status_code == status.HTTP_200_OK created_storage = response.json() - assert created_storage["component"]["name"] == create_request.name - assert created_storage["component"]["description"] == create_request.description - assert created_storage["component"]["type"] == EnergyComponentType.STORAGE.value + assert_energy_component(created_storage["component"], create_request, EnergyComponentType.STORAGE) assert created_storage["commodity"]["name"] == create_request.commodity diff --git a/tests/api/test_energy_transmissions.py b/tests/api/test_energy_transmissions.py index c316d60..c096db8 100644 --- a/tests/api/test_energy_transmissions.py +++ b/tests/api/test_energy_transmissions.py @@ -6,6 +6,7 @@ from ensysmod.model import EnergyComponentType from tests.utils import data_generator as data_gen +from tests.utils.assertions import assert_energy_component def test_create_energy_transmission(client: TestClient, normal_user_headers: Dict[str, str], db: Session): @@ -17,9 +18,7 @@ def test_create_energy_transmission(client: TestClient, normal_user_headers: Dic assert response.status_code == status.HTTP_200_OK created_transmission = response.json() - assert created_transmission["component"]["name"] == create_request.name - assert created_transmission["component"]["description"] == create_request.description - assert created_transmission["component"]["type"] == EnergyComponentType.TRANSMISSION.value + assert_energy_component(created_transmission["component"], create_request, EnergyComponentType.TRANSMISSION) assert created_transmission["commodity"]["name"] == create_request.commodity diff --git a/tests/utils/assertions.py b/tests/utils/assertions.py new file mode 100644 index 0000000..3b354d0 --- /dev/null +++ b/tests/utils/assertions.py @@ -0,0 +1,10 @@ +from typing import Dict + +from ensysmod.model import EnergyComponentType +from ensysmod.schemas import EnergyComponentCreate + + +def assert_energy_component(component: Dict, expected: EnergyComponentCreate, expected_type: EnergyComponentType): + assert component["type"] == expected_type.value + assert component["name"] == expected.name + assert component["description"] == expected.description From 46139b17fd1d822822deea7b1349d6d744c32e8c Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 9 Dec 2021 10:20:15 +0100 Subject: [PATCH 20/22] Added undefined energy component type --- ensysmod/model/energy_component.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ensysmod/model/energy_component.py b/ensysmod/model/energy_component.py index 4d8d875..58a1d64 100644 --- a/ensysmod/model/energy_component.py +++ b/ensysmod/model/energy_component.py @@ -9,6 +9,7 @@ class EnergyComponentType(enum.Enum): """ Enum for the different types of energy components. """ + UNDEFINED = 'UNDEFINED' # Undefined component (should not be used) SOURCE = 'SOURCE' SINK = 'SINK' CONVERSION = 'CONVERSION' From 1d688ed0be5c7fc700d85459055389d16c7e52a8 Mon Sep 17 00:00:00 2001 From: Paule <44635962+V3lop5@users.noreply.github.com> Date: Thu, 9 Dec 2021 10:28:53 +0100 Subject: [PATCH 21/22] Updated test cases for time series --- tests/api/test_ts_capacity_max.py | 1 - tests/api/test_ts_operation_rate_fix.py | 1 - tests/api/test_ts_operation_rate_max.py | 1 - 3 files changed, 3 deletions(-) diff --git a/tests/api/test_ts_capacity_max.py b/tests/api/test_ts_capacity_max.py index 7c9604f..f986f8f 100644 --- a/tests/api/test_ts_capacity_max.py +++ b/tests/api/test_ts_capacity_max.py @@ -25,7 +25,6 @@ def test_create_max_capacity(client: TestClient, normal_user_headers: Dict[str, """ create_request = get_random_max_capacity_create(db) response = client.post("/max-capacities/", headers=normal_user_headers, data=create_request.json()) - print(response.text) assert response.status_code == status.HTTP_200_OK created_ts = response.json() diff --git a/tests/api/test_ts_operation_rate_fix.py b/tests/api/test_ts_operation_rate_fix.py index 8f90e08..46816e5 100644 --- a/tests/api/test_ts_operation_rate_fix.py +++ b/tests/api/test_ts_operation_rate_fix.py @@ -25,7 +25,6 @@ def test_create_fix_operation_rate(client: TestClient, normal_user_headers: Dict """ create_request = get_random_fix_operation_rate_create(db) response = client.post("/fix-operation-rates/", headers=normal_user_headers, data=create_request.json()) - print(response.text) assert response.status_code == status.HTTP_200_OK created_ts = response.json() diff --git a/tests/api/test_ts_operation_rate_max.py b/tests/api/test_ts_operation_rate_max.py index 04c5069..652315f 100644 --- a/tests/api/test_ts_operation_rate_max.py +++ b/tests/api/test_ts_operation_rate_max.py @@ -25,7 +25,6 @@ def test_create_max_operation_rate(client: TestClient, normal_user_headers: Dict """ create_request = get_random_max_operation_rate_create(db) response = client.post("/max-operation-rates/", headers=normal_user_headers, data=create_request.json()) - print(response.text) assert response.status_code == status.HTTP_200_OK created_ts = response.json() From 619f2216ebb529cf72a551bd04bfde79c60e7b1e Mon Sep 17 00:00:00 2001 From: Melanie Ecker Date: Thu, 9 Dec 2021 10:28:54 +0100 Subject: [PATCH 22/22] Updated documentation --- docs/source/api.rst | 7 ------- docs/source/index.rst | 2 -- docs/source/modelUser.rst | 13 ------------- 3 files changed, 22 deletions(-) delete mode 100644 docs/source/api.rst delete mode 100644 docs/source/modelUser.rst diff --git a/docs/source/api.rst b/docs/source/api.rst deleted file mode 100644 index 1bdfb0d..0000000 --- a/docs/source/api.rst +++ /dev/null @@ -1,7 +0,0 @@ -API -=== - -.. autosummary:: - :toctree: generated - - counter \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 26820d7..7aede79 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -25,6 +25,4 @@ Indices and tables usage endpoints - modelUser - api projectStructure diff --git a/docs/source/modelUser.rst b/docs/source/modelUser.rst deleted file mode 100644 index 8714891..0000000 --- a/docs/source/modelUser.rst +++ /dev/null @@ -1,13 +0,0 @@ -User -==== - -Well a user is a user. I guess. - -Class description: - -.. automodule:: ensysmod.model -.. autoclass:: User - :members: - :member-order: bysource - - .. automethod:: __init__ \ No newline at end of file