From 77da72e3c02a7dca340441dbcdf12ed822a92959 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Thu, 26 Sep 2024 14:27:23 +0200 Subject: [PATCH 1/9] Update deprecated function/make syntax more concise --- ixmp4/data/api/base.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ixmp4/data/api/base.py b/ixmp4/data/api/base.py index 9faa6f76..fa1403cd 100644 --- a/ixmp4/data/api/base.py +++ b/ixmp4/data/api/base.py @@ -167,10 +167,7 @@ def retry(max_retries=max_retries) -> dict | list | None: **kwargs, ) - if params is None: - params = {} - else: - params = self.sanitize_params(params) + params = self.sanitize_params(params) if params else {} try: res = self.backend.client.request( @@ -181,7 +178,7 @@ def retry(max_retries=max_retries) -> dict | list | None: **kwargs, ) except httpx.ReadTimeout: - logger.warn("Read timeout, retrying request...") + logger.warning("Read timeout, retrying request...") return retry() return self._handle_response(res, retry) From 99c247572e6cb5be4e24cef4c6a176c86a99b2a0 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Thu, 26 Sep 2024 14:31:15 +0200 Subject: [PATCH 2/9] Fix typo in docstring --- ixmp4/server/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ixmp4/server/__init__.py b/ixmp4/server/__init__.py index 651c1728..420e9179 100644 --- a/ixmp4/server/__init__.py +++ b/ixmp4/server/__init__.py @@ -7,7 +7,7 @@ ixmp4 server start [--host 127.0.0.1] [--port 8000] This will start ixmp4’s asgi server. Check -``http://127.0.0.1:8000/v1//docs``. +``http://127.0.0.1:8000/v1//docs/``. """ From acc0fcf1522159b00ed28ae9b01cca976c4774f7 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Thu, 26 Sep 2024 14:31:24 +0200 Subject: [PATCH 3/9] Disable raising server exceptions --- ixmp4/data/backend/api.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ixmp4/data/backend/api.py b/ixmp4/data/backend/api.py index ba0cd4ab..d03f7178 100644 --- a/ixmp4/data/backend/api.py +++ b/ixmp4/data/backend/api.py @@ -153,6 +153,7 @@ def make_client(self, rest_url: str, auth: BaseAuth): self.client = TestClient( app=app, base_url=rest_url, + raise_server_exceptions=False, ) app.dependency_overrides[deps.validate_token] = deps.do_not_validate_token From 44aca9d01fa671c84f2f1f86222515ef7c29b641 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Mon, 30 Sep 2024 09:42:21 +0200 Subject: [PATCH 4/9] Create own errors for optimization items/data --- ixmp4/core/exceptions.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/ixmp4/core/exceptions.py b/ixmp4/core/exceptions.py index 77358b37..d665b52b 100644 --- a/ixmp4/core/exceptions.py +++ b/ixmp4/core/exceptions.py @@ -178,12 +178,17 @@ class InvalidCredentials(IxmpError): http_error_name = "invalid_credentials" +# == Optimization == + + +class OptimizationDataValidationError(IxmpError): + http_status_code = 431 + http_error_name = "optimization_data_validation_error" + + # == Optimization.Table == -class OptimizationTableDataKeysNotUnique(NotUnique): - _message = ( - "The keys of the Table's data are not unique. Please consider using " - "`constrained_to_indexsets` to specify the IndexSet identifiers." - ) - http_error_name = "optimization_table_data_keys_not_unique" +class OptimizationTableUsageError(IxmpError): + http_status_code = 432 + http_error_name = "optimization_table_usage_error" From 89bd0dea8ba1561f678514e5b224c4810acbd8b0 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Mon, 30 Sep 2024 09:44:45 +0200 Subject: [PATCH 5/9] Raise own Table error rather than ValueError --- ixmp4/data/db/optimization/base.py | 6 ++++++ ixmp4/data/db/optimization/table/model.py | 6 +++++- ixmp4/data/db/optimization/utils.py | 20 +++++++++++------ tests/core/test_table.py | 26 +++++++++++++++++------ tests/data/test_optimization_table.py | 26 +++++++++++++++++------ 5 files changed, 65 insertions(+), 19 deletions(-) diff --git a/ixmp4/data/db/optimization/base.py b/ixmp4/data/db/optimization/base.py index 522fd7ae..7c3cc084 100644 --- a/ixmp4/data/db/optimization/base.py +++ b/ixmp4/data/db/optimization/base.py @@ -1,3 +1,6 @@ +from typing import ClassVar + +from ixmp4.core.exceptions import IxmpError from ixmp4.data import types from .. import mixins @@ -16,6 +19,9 @@ class BaseModel(RootBaseModel, mixins.HasCreationInfo): + # NOTE: only subclasses storing data actually define this! + DataInvalid: ClassVar[type[IxmpError]] + __abstract__ = True table_prefix = "optimization_" diff --git a/ixmp4/data/db/optimization/table/model.py b/ixmp4/data/db/optimization/table/model.py index 5347f0bb..ea99cd11 100644 --- a/ixmp4/data/db/optimization/table/model.py +++ b/ixmp4/data/db/optimization/table/model.py @@ -4,6 +4,7 @@ from sqlalchemy.orm import validates from ixmp4 import db +from ixmp4.core.exceptions import OptimizationDataValidationError from ixmp4.data import types from ixmp4.data.abstract import optimization as abstract @@ -14,6 +15,7 @@ class Table(base.BaseModel): # NOTE: These might be mixin-able, but would require some abstraction NotFound: ClassVar = abstract.Table.NotFound NotUnique: ClassVar = abstract.Table.NotUnique + DataInvalid: ClassVar = OptimizationDataValidationError DeletionPrevented: ClassVar = abstract.Table.DeletionPrevented # constrained_to_indexsets: ClassVar[list[str] | None] = None @@ -22,10 +24,12 @@ class Table(base.BaseModel): columns: types.Mapped[list["Column"]] = db.relationship() data: types.JsonDict = db.Column(db.JsonType, nullable=False, default={}) + # TODO: should we pass self to validate_data to raise more specific errors? + @validates("data") def validate_data(self, key, data: dict[str, Any]): return utils.validate_data( - key=key, + host=self, data=data, columns=self.columns, ) diff --git a/ixmp4/data/db/optimization/utils.py b/ixmp4/data/db/optimization/utils.py index 78b517d0..f375df1e 100644 --- a/ixmp4/data/db/optimization/utils.py +++ b/ixmp4/data/db/optimization/utils.py @@ -2,6 +2,8 @@ import pandas as pd +from . import base + if TYPE_CHECKING: from .column import Column @@ -17,37 +19,43 @@ def collect_indexsets_to_check( return collection -def validate_data(key, data: dict[str, Any], columns: list["Column"]): +def validate_data(host: base.BaseModel, data: dict[str, Any], columns: list["Column"]): data_frame: pd.DataFrame = pd.DataFrame.from_dict(data) # TODO for all of the following, we might want to create unique exceptions # Could me make both more specific by specifiying missing/extra columns? if len(data_frame.columns) < len(columns): - raise ValueError( + raise host.DataInvalid( + f"While handling {host.__str__}: \n" f"Data is missing for some Columns! \n Data: {data} \n " f"Columns: {[column.name for column in columns]}" ) elif len(data_frame.columns) > len(columns): - raise ValueError( + raise host.DataInvalid( + f"While handling {host.__str__}: \n" f"Trying to add data to unknown Columns! \n Data: {data} \n " f"Columns: {[column.name for column in columns]}" ) # We could make this more specific maybe by pointing to the missing values if data_frame.isna().any(axis=None): - raise ValueError( + raise host.DataInvalid( + f"While handling {host.__str__}: \n" "The data is missing values, please make sure it " "does not contain None or NaN, either!" ) # We can make this more specific e.g. highlighting all duplicate rows via # pd.DataFrame.duplicated(keep="False") if data_frame.value_counts().max() > 1: - raise ValueError("The data contains duplicate rows!") + raise host.DataInvalid( + f"While handling {host.__str__}: \n" "The data contains duplicate rows!" + ) # Can we make this more specific? Iterating over columns; if any is False, # return its name or something? limited_to_indexsets = collect_indexsets_to_check(columns=columns) if not data_frame.isin(limited_to_indexsets).all(axis=None): - raise ValueError( + raise host.DataInvalid( + f"While handling {host.__str__}: \n" "The data contains values that are not allowed as per the IndexSets " "and Columns it is constrained to!" ) diff --git a/tests/core/test_table.py b/tests/core/test_table.py index bc45a22a..493e163e 100644 --- a/tests/core/test_table.py +++ b/tests/core/test_table.py @@ -3,6 +3,7 @@ import ixmp4 from ixmp4.core import IndexSet, Table +from ixmp4.core.exceptions import OptimizationDataValidationError from ..utils import create_indexsets_for_run @@ -138,19 +139,24 @@ def test_table_add_data(self, platform: ixmp4.Platform): constrained_to_indexsets=[indexset.name, indexset_2.name], ) - with pytest.raises(ValueError, match="missing values"): + with pytest.raises(OptimizationDataValidationError, match="missing values"): table_2.add( pd.DataFrame({indexset.name: [None], indexset_2.name: [2]}), # empty string is allowed for now, but None or NaN raise ) - with pytest.raises(ValueError, match="contains duplicate rows"): + with pytest.raises( + OptimizationDataValidationError, match="contains duplicate rows" + ): table_2.add( data={indexset.name: ["foo", "foo"], indexset_2.name: [2, 2]}, ) # Test raising on unrecognised data.values() - with pytest.raises(ValueError, match="contains values that are not allowed"): + with pytest.raises( + OptimizationDataValidationError, + match="contains values that are not allowed", + ): table_2.add( data={indexset.name: ["foo"], indexset_2.name: [0]}, ) @@ -164,7 +170,9 @@ def test_table_add_data(self, platform: ixmp4.Platform): constrained_to_indexsets=[indexset.name, indexset_2.name], column_names=["Column 1", "Column 2"], ) - with pytest.raises(ValueError, match="Data is missing for some Columns!"): + with pytest.raises( + OptimizationDataValidationError, match="Data is missing for some Columns!" + ): table_3.add(data={"Column 1": ["bar"]}) test_data_3 = {"Column 1": ["bar"], "Column 2": [2]} @@ -178,7 +186,10 @@ def test_table_add_data(self, platform: ixmp4.Platform): assert table_3.data == {"Column 1": ["bar", "foo"], "Column 2": [2, 3]} # Test raising on non-existing Column.name - with pytest.raises(ValueError, match="Trying to add data to unknown Columns!"): + with pytest.raises( + OptimizationDataValidationError, + match="Trying to add data to unknown Columns!", + ): table_3.add({"Column 3": [1]}) # Test that order is not important... @@ -196,7 +207,10 @@ def test_table_add_data(self, platform: ixmp4.Platform): assert table_4.data == {"Column 2": [2, 1], "Column 1": ["bar", "foo"]} # This doesn't seem to test a distinct case compared to the above - with pytest.raises(ValueError, match="Trying to add data to unknown Columns!"): + with pytest.raises( + OptimizationDataValidationError, + match="Trying to add data to unknown Columns!", + ): table_4.add( data={"Column 1": ["bar"], "Column 2": [3], indexset.name: ["foo"]}, ) diff --git a/tests/data/test_optimization_table.py b/tests/data/test_optimization_table.py index 7b03e489..2157c160 100644 --- a/tests/data/test_optimization_table.py +++ b/tests/data/test_optimization_table.py @@ -3,6 +3,7 @@ import ixmp4 from ixmp4 import Table +from ixmp4.core.exceptions import OptimizationDataValidationError from ..utils import create_indexsets_for_run @@ -146,21 +147,26 @@ def test_table_add_data(self, platform: ixmp4.Platform): constrained_to_indexsets=[indexset_1.name, indexset_2.name], ) - with pytest.raises(ValueError, match="missing values"): + with pytest.raises(OptimizationDataValidationError, match="missing values"): platform.backend.optimization.tables.add_data( table_id=table_2.id, data=pd.DataFrame({indexset_1.name: [None], indexset_2.name: [2]}), # empty string is allowed for now (see below), but None or NaN raise ) - with pytest.raises(ValueError, match="contains duplicate rows"): + with pytest.raises( + OptimizationDataValidationError, match="contains duplicate rows" + ): platform.backend.optimization.tables.add_data( table_id=table_2.id, data={indexset_1.name: ["foo", "foo"], indexset_2.name: [2, 2]}, ) # Test raising on unrecognised data.values() - with pytest.raises(ValueError, match="contains values that are not allowed"): + with pytest.raises( + OptimizationDataValidationError, + match="contains values that are not allowed", + ): platform.backend.optimization.tables.add_data( table_id=table_2.id, data={indexset_1.name: ["foo"], indexset_2.name: [0]}, @@ -181,7 +187,9 @@ def test_table_add_data(self, platform: ixmp4.Platform): constrained_to_indexsets=[indexset_1.name, indexset_2.name], column_names=["Column 1", "Column 2"], ) - with pytest.raises(ValueError, match="Data is missing for some Columns!"): + with pytest.raises( + OptimizationDataValidationError, match="Data is missing for some Columns!" + ): platform.backend.optimization.tables.add_data( table_id=table_3.id, data={"Column 1": ["bar"]} ) @@ -206,7 +214,10 @@ def test_table_add_data(self, platform: ixmp4.Platform): assert table_3.data == {"Column 1": ["bar", "foo"], "Column 2": [2, 3]} # Test raising on non-existing Column.name - with pytest.raises(ValueError, match="Trying to add data to unknown Columns!"): + with pytest.raises( + OptimizationDataValidationError, + match="Trying to add data to unknown Columns!", + ): platform.backend.optimization.tables.add_data( table_id=table_3.id, data={"Column 3": [1]} ) @@ -237,7 +248,10 @@ def test_table_add_data(self, platform: ixmp4.Platform): assert table_4.data == {"Column 2": [2, 1], "Column 1": ["bar", "foo"]} # This doesn't seem to test a distinct case compared to the above - with pytest.raises(ValueError, match="Trying to add data to unknown Columns!"): + with pytest.raises( + OptimizationDataValidationError, + match="Trying to add data to unknown Columns!", + ): platform.backend.optimization.tables.add_data( table_id=table_4.id, data={"Column 1": ["bar"], "Column 2": [3], "Indexset": ["foo"]}, From beb2e8a0d2cc30fb525e1bd3b3a62f7b42d676b0 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Mon, 30 Sep 2024 09:48:01 +0200 Subject: [PATCH 6/9] Raise own Table.create() error rather than ValueError --- ixmp4/data/db/optimization/table/repository.py | 9 ++++++--- tests/core/test_table.py | 11 ++++++++--- tests/data/test_optimization_table.py | 11 ++++++++--- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/ixmp4/data/db/optimization/table/repository.py b/ixmp4/data/db/optimization/table/repository.py index ceed1629..17738a3d 100644 --- a/ixmp4/data/db/optimization/table/repository.py +++ b/ixmp4/data/db/optimization/table/repository.py @@ -3,6 +3,7 @@ import pandas as pd from ixmp4 import db +from ixmp4.core.exceptions import OptimizationTableUsageError from ixmp4.data.abstract import optimization as abstract from ixmp4.data.auth.decorators import guard @@ -19,6 +20,8 @@ class TableRepository( ): model_class = Table + UsageError = OptimizationTableUsageError + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.docs = TableDocsRepository(*args, **kwargs) @@ -108,16 +111,16 @@ def create( if isinstance(constrained_to_indexsets, str): constrained_to_indexsets = list(constrained_to_indexsets) if column_names and len(column_names) != len(constrained_to_indexsets): - raise ValueError( + raise self.UsageError( "`constrained_to_indexsets` and `column_names` not equal in length! " "Please provide the same number of entries for both!" ) # TODO: activate something like this if each column must be indexed by a unique # indexset # if len(constrained_to_indexsets) != len(set(constrained_to_indexsets)): - # raise ValueError("Each dimension must be constrained to a unique indexset!") # noqa + # raise self.UsageError("Each dimension must be constrained to a unique indexset!") # noqa if column_names and len(column_names) != len(set(column_names)): - raise ValueError("The given `column_names` are not unique!") + raise self.UsageError("The given `column_names` are not unique!") table = super().create( run_id=run_id, diff --git a/tests/core/test_table.py b/tests/core/test_table.py index 493e163e..0fd081c9 100644 --- a/tests/core/test_table.py +++ b/tests/core/test_table.py @@ -3,7 +3,10 @@ import ixmp4 from ixmp4.core import IndexSet, Table -from ixmp4.core.exceptions import OptimizationDataValidationError +from ixmp4.core.exceptions import ( + OptimizationDataValidationError, + OptimizationTableUsageError, +) from ..utils import create_indexsets_for_run @@ -61,7 +64,7 @@ def test_create_table(self, platform: ixmp4.Platform): ) # Test mismatch in constrained_to_indexsets and column_names raises - with pytest.raises(ValueError, match="not equal in length"): + with pytest.raises(OptimizationTableUsageError, match="not equal in length"): _ = run.optimization.tables.create( name="Table 2", constrained_to_indexsets=[indexset.name], @@ -77,7 +80,9 @@ def test_create_table(self, platform: ixmp4.Platform): assert table_2.columns[0].name == "Column 1" # Test duplicate column_names raise - with pytest.raises(ValueError, match="`column_names` are not unique"): + with pytest.raises( + OptimizationTableUsageError, match="`column_names` are not unique" + ): _ = run.optimization.tables.create( name="Table 3", constrained_to_indexsets=[indexset.name, indexset.name], diff --git a/tests/data/test_optimization_table.py b/tests/data/test_optimization_table.py index 2157c160..4eaef13e 100644 --- a/tests/data/test_optimization_table.py +++ b/tests/data/test_optimization_table.py @@ -3,7 +3,10 @@ import ixmp4 from ixmp4 import Table -from ixmp4.core.exceptions import OptimizationDataValidationError +from ixmp4.core.exceptions import ( + OptimizationDataValidationError, + OptimizationTableUsageError, +) from ..utils import create_indexsets_for_run @@ -57,7 +60,7 @@ def test_create_table(self, platform: ixmp4.Platform): ) # Test mismatch in constrained_to_indexsets and column_names raises - with pytest.raises(ValueError, match="not equal in length"): + with pytest.raises(OptimizationTableUsageError, match="not equal in length"): _ = platform.backend.optimization.tables.create( run_id=run.id, name="Table 2", @@ -75,7 +78,9 @@ def test_create_table(self, platform: ixmp4.Platform): assert table_2.columns[0].name == "Column 1" # Test duplicate column_names raise - with pytest.raises(ValueError, match="`column_names` are not unique"): + with pytest.raises( + OptimizationTableUsageError, match="`column_names` are not unique" + ): _ = platform.backend.optimization.tables.create( run_id=run.id, name="Table 3", From e3fb75eee5af269e0bd9076af3502ba91290e688 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Mon, 30 Sep 2024 09:49:46 +0200 Subject: [PATCH 7/9] Raise own IndexSet error rather than ValueError --- ixmp4/data/db/optimization/indexset/model.py | 6 +++++- tests/core/test_indexset.py | 5 +++-- tests/data/test_optimization_indexset.py | 5 +++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ixmp4/data/db/optimization/indexset/model.py b/ixmp4/data/db/optimization/indexset/model.py index e772f6aa..896692a4 100644 --- a/ixmp4/data/db/optimization/indexset/model.py +++ b/ixmp4/data/db/optimization/indexset/model.py @@ -3,6 +3,7 @@ from sqlalchemy.orm import validates from ixmp4 import db +from ixmp4.core.exceptions import OptimizationDataValidationError from ixmp4.data import types from ixmp4.data.abstract import optimization as abstract @@ -12,6 +13,7 @@ class IndexSet(base.BaseModel): NotFound: ClassVar = abstract.IndexSet.NotFound NotUnique: ClassVar = abstract.IndexSet.NotUnique + DataInvalid: ClassVar = OptimizationDataValidationError DeletionPrevented: ClassVar = abstract.IndexSet.DeletionPrevented elements: types.JsonList = db.Column(db.JsonType, nullable=False, default=[]) @@ -21,7 +23,9 @@ def validate_elements(self, key, value: list[float | int | str]): unique = set() for element in value: if element in unique: - raise ValueError(f"{element} already defined for IndexSet {self.name}!") + raise self.DataInvalid( + f"{element} already defined for IndexSet {self.name}!" + ) else: unique.add(element) return value diff --git a/tests/core/test_indexset.py b/tests/core/test_indexset.py index d1556289..eb0654ed 100644 --- a/tests/core/test_indexset.py +++ b/tests/core/test_indexset.py @@ -4,6 +4,7 @@ import ixmp4 from ixmp4.core import IndexSet +from ixmp4.core.exceptions import OptimizationDataValidationError from ..utils import create_indexsets_for_run @@ -67,10 +68,10 @@ def test_add_elements(self, platform: ixmp4.Platform): assert indexset_1.elements == indexset_2.elements - with pytest.raises(ValueError): + with pytest.raises(OptimizationDataValidationError): indexset_1.add(["baz", "foo"]) - with pytest.raises(ValueError): + with pytest.raises(OptimizationDataValidationError): indexset_2.add(["baz", "baz"]) indexset_1.add(1) diff --git a/tests/data/test_optimization_indexset.py b/tests/data/test_optimization_indexset.py index 3c67a027..9eb4e094 100644 --- a/tests/data/test_optimization_indexset.py +++ b/tests/data/test_optimization_indexset.py @@ -3,6 +3,7 @@ import pytest import ixmp4 +from ixmp4.core.exceptions import OptimizationDataValidationError from ixmp4.data.abstract import IndexSet from ..utils import create_indexsets_for_run @@ -150,12 +151,12 @@ def test_add_elements(self, platform: ixmp4.Platform): ).elements ) - with pytest.raises(ValueError): + with pytest.raises(OptimizationDataValidationError): platform.backend.optimization.indexsets.add_elements( indexset_id=indexset_1.id, elements=["baz", "foo"] ) - with pytest.raises(ValueError): + with pytest.raises(OptimizationDataValidationError): platform.backend.optimization.indexsets.add_elements( indexset_id=indexset_2.id, elements=["baz", "baz"] ) From a468267d8fe3e287baeb776a40e86fc7a3446dc7 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Mon, 30 Sep 2024 10:23:50 +0200 Subject: [PATCH 8/9] Use function form of __str__ as suggested --- ixmp4/data/db/optimization/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ixmp4/data/db/optimization/utils.py b/ixmp4/data/db/optimization/utils.py index f375df1e..08c5c721 100644 --- a/ixmp4/data/db/optimization/utils.py +++ b/ixmp4/data/db/optimization/utils.py @@ -25,13 +25,13 @@ def validate_data(host: base.BaseModel, data: dict[str, Any], columns: list["Col # Could me make both more specific by specifiying missing/extra columns? if len(data_frame.columns) < len(columns): raise host.DataInvalid( - f"While handling {host.__str__}: \n" + f"While handling {host.__str__()}: \n" f"Data is missing for some Columns! \n Data: {data} \n " f"Columns: {[column.name for column in columns]}" ) elif len(data_frame.columns) > len(columns): raise host.DataInvalid( - f"While handling {host.__str__}: \n" + f"While handling {host.__str__()}: \n" f"Trying to add data to unknown Columns! \n Data: {data} \n " f"Columns: {[column.name for column in columns]}" ) @@ -39,7 +39,7 @@ def validate_data(host: base.BaseModel, data: dict[str, Any], columns: list["Col # We could make this more specific maybe by pointing to the missing values if data_frame.isna().any(axis=None): raise host.DataInvalid( - f"While handling {host.__str__}: \n" + f"While handling {host.__str__()}: \n" "The data is missing values, please make sure it " "does not contain None or NaN, either!" ) @@ -47,7 +47,7 @@ def validate_data(host: base.BaseModel, data: dict[str, Any], columns: list["Col # pd.DataFrame.duplicated(keep="False") if data_frame.value_counts().max() > 1: raise host.DataInvalid( - f"While handling {host.__str__}: \n" "The data contains duplicate rows!" + f"While handling {host.__str__()}: \n" "The data contains duplicate rows!" ) # Can we make this more specific? Iterating over columns; if any is False, @@ -55,7 +55,7 @@ def validate_data(host: base.BaseModel, data: dict[str, Any], columns: list["Col limited_to_indexsets = collect_indexsets_to_check(columns=columns) if not data_frame.isin(limited_to_indexsets).all(axis=None): raise host.DataInvalid( - f"While handling {host.__str__}: \n" + f"While handling {host.__str__()}: \n" "The data contains values that are not allowed as per the IndexSets " "and Columns it is constrained to!" ) From 34c337f55d6e87d601820733923aa278a7935384 Mon Sep 17 00:00:00 2001 From: Fridolin Glatter Date: Mon, 30 Sep 2024 10:24:06 +0200 Subject: [PATCH 9/9] Use suggested http status codes --- ixmp4/core/exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ixmp4/core/exceptions.py b/ixmp4/core/exceptions.py index d665b52b..6c64a12b 100644 --- a/ixmp4/core/exceptions.py +++ b/ixmp4/core/exceptions.py @@ -182,7 +182,7 @@ class InvalidCredentials(IxmpError): class OptimizationDataValidationError(IxmpError): - http_status_code = 431 + http_status_code = 422 http_error_name = "optimization_data_validation_error" @@ -190,5 +190,5 @@ class OptimizationDataValidationError(IxmpError): class OptimizationTableUsageError(IxmpError): - http_status_code = 432 + http_status_code = 422 http_error_name = "optimization_table_usage_error"