Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/python api #16

Merged
merged 22 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ typedef int32_t PGM_IO_ID;
* @brief Opaque struct for the VnfConverter class.
*
*/
typedef struct PGM_IO_VnfConverter PGM_IO_VnfConverter;
typedef struct PGM_IO_VnfPgmConverter PGM_IO_VnfPgmConverter;

/**
* @brief Opaque struct for the handle class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,29 @@ extern "C" {
#endif

/**
* @brief Create the PGM_IO_VnfConverter
* @brief Create the PGM_IO_VnfPgmConverter
* @param handle
* @param file_buffer A pointer to the null-terminated C string.
* @return The pointer to a PGM_IO_VnfConverter instance. The instance must be freed by
* @return The pointer to a PGM_IO_VnfPgmConverter instance. The instance must be freed by
* PGM_IO_destroy_vnf_converter.
*/
PGM_IO_API PGM_IO_VnfConverter* PGM_IO_create_vnf_converter(PGM_IO_Handle* handle, char const* file_buffer,
PGM_IO_ExperimentalFeatures experimental_features);
PGM_IO_API PGM_IO_VnfPgmConverter* PGM_IO_create_vnf_converter(PGM_IO_Handle* handle, char const* file_buffer,
PGM_IO_ExperimentalFeatures experimental_features);

/**
* @brief Retrieve the transformed input data from .vnf format to PGM format
* @param handle
* @param converter_ptr A pointer to a PGM_IO_VnfConverter instace.
* @param dataset A pointer to the const dataset supplied by the user.
* @return The pointer to the const dataset instance supplied by the user which has been filled in.
* @param converter_ptr A pointer to a PGM_IO_VnfPgmConverter instace.
* @return The pointer to the json string instance that holds data in PGM format.
*/
PGM_IO_API char const* PGM_IO_get_vnf_input_data(PGM_IO_Handle* handle, PGM_IO_VnfConverter* converter_ptr);
PGM_IO_API char const* PGM_IO_vnf_pgm_converter_get_input_data(PGM_IO_Handle* handle,
PGM_IO_VnfPgmConverter* converter_ptr);

/**
* @brief Destroy the PGM_IO_VnfConverter and free up the memory that was dedicated to it.
* @param converter_ptr A pointer to a PGM_IO_VnfConverter instance.
* @brief Destroy the PGM_IO_VnfPgmConverter and free up the memory that was dedicated to it.
* @param converter_ptr A pointer to a PGM_IO_VnfPgmConverter instance.
*/
PGM_IO_API void PGM_IO_destroy_vnf_converter(PGM_IO_VnfConverter* converter_ptr);
PGM_IO_API void PGM_IO_destroy_vnf_converter(PGM_IO_VnfPgmConverter* converter_ptr);

#ifdef __cplusplus
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

namespace pgm_io = power_grid_model_io_native;

struct PGM_IO_VnfConverter : public pgm_io::PgmVnfConverter {
struct PGM_IO_VnfPgmConverter : public pgm_io::PgmVnfConverter {
using PgmVnfConverter::PgmVnfConverter;
};

PGM_IO_VnfConverter* PGM_IO_create_vnf_converter(PGM_IO_Handle* handle, char const* file_buffer,
PGM_IO_ExperimentalFeatures experimental_features) {
PGM_IO_VnfPgmConverter* PGM_IO_create_vnf_converter(PGM_IO_Handle* handle, char const* file_buffer,
PGM_IO_ExperimentalFeatures experimental_features) {
return call_with_catch(
handle,
[file_buffer, experimental_features] {
Expand All @@ -37,16 +37,16 @@ PGM_IO_VnfConverter* PGM_IO_create_vnf_converter(PGM_IO_Handle* handle, char con
default:
throw power_grid_model::MissingCaseForEnumError{"PGM_IO_create_vnf_converter", experimental_features};
}
auto* converter = new PGM_IO_VnfConverter(file_buffer, experimental_feature);
auto* converter = new PGM_IO_VnfPgmConverter(file_buffer, experimental_feature);
parse_vnf_file_wrapper(converter);
return converter;
},
PGM_IO_regular_error);
}

char const* PGM_IO_get_vnf_input_data(PGM_IO_Handle* handle, PGM_IO_VnfConverter* converter_ptr) {
char const* PGM_IO_vnf_pgm_converter_get_input_data(PGM_IO_Handle* handle, PGM_IO_VnfPgmConverter* converter_ptr) {
return call_with_catch(
handle, [converter_ptr] { return convert_input_wrapper(converter_ptr).c_str(); }, PGM_IO_regular_error);
}

void PGM_IO_destroy_vnf_converter(PGM_IO_VnfConverter* converter_ptr) { delete converter_ptr; }
void PGM_IO_destroy_vnf_converter(PGM_IO_VnfPgmConverter* converter_ptr) { delete converter_ptr; }
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def generate_build_ext(pkg_dir: Path, pkg_name: str):
libraries: list[str] = []
sources = [
str(pgm_io_c / pgm_io_c / "src" / "handle.cpp"),
str(pgm_io_c / pgm_io_c / "src" / "vnf_pgm_converter.cpp"),
]
# macro
define_macros = [
Expand Down
98 changes: 98 additions & 0 deletions src/power_grid_model_io_native/_core/error_handling.py
Laurynas-Jagutis marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0

"""
Error handling
"""

from power_grid_model._core.error_handling import (
PGM_NO_ERROR,
PGM_REGULAR_ERROR,
PGM_SERIALIZATION_ERROR,
VALIDATOR_MSG,
PowerGridBatchError,
PowerGridSerializationError,
_interpret_error,
)

from power_grid_model_io_native._core.power_grid_model_io_core import pgm_io_core as pgmic

# def _interpret_error_pgm_io(message: str, decode_error: bool = True) -> PowerGridError:
# if decode_error:
# for pattern, type_ in _ERROR_MESSAGE_PATTERNS.items():
# if pattern.search(message) is not None:
# return type_(message)

# return PowerGridError(message)


def find_error(batch_size: int = 1, decode_error: bool = True) -> RuntimeError | None:
"""
Check if there is an error and return it

Args:
batch_size: (int, optional): Size of batch. Defaults to 1.
decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True

Returns: error object, can be none

"""
_ = batch_size
error_code: int = pgmic.error_code()
if error_code == PGM_NO_ERROR:
return None
if error_code == PGM_REGULAR_ERROR:
error_message = pgmic.error_message()
error_message += VALIDATOR_MSG
return _interpret_error(error_message, decode_error=decode_error)
if error_code == PGM_SERIALIZATION_ERROR:
return PowerGridSerializationError(pgmic.error_message())
return RuntimeError("Unknown error!")
mgovers marked this conversation as resolved.
Show resolved Hide resolved


def assert_no_error(batch_size: int = 1, decode_error: bool = True):
"""
Assert there is no error in the last operation
If there is an error, raise it

Args:
batch_size (int, optional): Size of batch. Defaults to 1.
decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True

Returns:

"""
error = find_error(batch_size=batch_size, decode_error=decode_error)
if error is not None:
raise error


def handle_errors(
continue_on_batch_error: bool, batch_size: int = 1, decode_error: bool = True
) -> PowerGridBatchError | None:
"""
Handle any errors in the way that is specified.

Args:
continue_on_batch_error (bool): Return the error when the error type is a batch error instead of reraising it.
batch_size (int, optional): Size of batch. Defaults to 1.
decode_error (bool, optional): Decode the error message(s) to derived error classes. Defaults to True

Raises:
error: Any errors previously encountered, unless it was a batch error and continue_on_batch_error was True.

Returns:
PowerGridBatchError | None: None if there were no errors, or the previously encountered
error if it was a batch error and continue_on_batch_error was True.
"""
error: RuntimeError | None = find_error(batch_size=batch_size, decode_error=decode_error)
if error is None:
return None

if continue_on_batch_error and isinstance(error, PowerGridBatchError):
# continue on batch error
return error

# raise normal error
raise error
24 changes: 21 additions & 3 deletions src/power_grid_model_io_native/_core/power_grid_model_io_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from inspect import signature
from itertools import chain
from pathlib import Path
from typing import Callable, Optional
from typing import Callable

from power_grid_model._core.power_grid_core import CharPtr, CStr, IdxC

Expand All @@ -27,6 +27,12 @@ class HandlePtr(c_void_p):
"""


class PgmVnfConverterPtr(c_void_p):
"""
Pointer to PgmVnfConverter
"""


def _load_core() -> CDLL:
"""

Expand Down Expand Up @@ -112,9 +118,9 @@ class PowerGridModelIoCore:
"""

_handle: HandlePtr
_instance: Optional["PowerGridModelIoCore"] = None
_instance: "PowerGridModelIoCore | None" = None

# singleton of power grid core
# singleton of power grid model io core
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls, *args, **kwargs)
Expand All @@ -139,6 +145,18 @@ def error_code(self) -> int: # type: ignore[empty-body]
def error_message(self) -> str: # type: ignore[empty-body]
pass # pragma: no cover

@make_c_binding
def create_vnf_converter(self, data: str, experim_feature: int) -> PgmVnfConverterPtr: # type: ignore[empty-body]
pass # pragma: no cover

@make_c_binding
def vnf_pgm_converter_get_input_data(self, pgmvnfconverter: PgmVnfConverterPtr) -> str: # type: ignore[empty-body]
pass # pragma: no cover

@make_c_binding
def destroy_vnf_converter(self, pgmvnfconverter: PgmVnfConverterPtr) -> None: # type: ignore[empty-body]
pass # pragma: no cover


# make one instance
pgm_io_core = PowerGridModelIoCore()
44 changes: 44 additions & 0 deletions src/power_grid_model_io_native/_core/vnf_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0

"""
Power grid model io native converter for vnf files
"""

from power_grid_model_io_native._core.error_handling import assert_no_error
from power_grid_model_io_native._core.power_grid_model_io_core import PgmVnfConverterPtr, pgm_io_core as pgmic


class PgmVnfConverter:
"""A converter class which will convert a given string representation of .vnf data to the PowerGridModel format"""

_pgm_vnf_converter: PgmVnfConverterPtr
_serialized_data: str

def __new__(
cls,
string_buffer: str,
experimental_feature: int,
):
instance = super().__new__(cls)

instance._pgm_vnf_converter = pgmic.create_vnf_converter(string_buffer, experimental_feature)
assert_no_error()

return instance

def __del__(self):
if hasattr(self, "_pgm_vnf_converter"):
pgmic.destroy_vnf_converter(self._pgm_vnf_converter)

def get_pgm_input_data(self):
"""A function of the PgmVnfConverter class which will convert and return the data in PGM format

Returns:
str: json data in PGM format
"""
pgm_data = pgmic.vnf_pgm_converter_get_input_data(self._pgm_vnf_converter)
assert_no_error()
self._serialized_data = pgm_data
return self._serialized_data
3 changes: 3 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0
2 changes: 1 addition & 1 deletion tests/c_api_tests/test_c_api_vnf_converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ TEST_CASE("Test PGM_IO_get_vnf_input_data") {
auto converter = PGM_IO_create_vnf_converter(handle, "", experimental_feature_flag);
CHECK(converter != nullptr);

auto json_result = PGM_IO_get_vnf_input_data(handle, converter);
auto json_result = PGM_IO_vnf_pgm_converter_get_input_data(handle, converter);
std::string_view json_string = R"({"version":"1.0","type":"input","is_batch":false,"attributes":{},"data":{}})";
CHECK(json_string == json_result);

Expand Down
3 changes: 3 additions & 0 deletions tests/unit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
#
# SPDX-License-Identifier: MPL-2.0
27 changes: 23 additions & 4 deletions tests/unit/test_vnf_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,28 @@
#
# SPDX-License-Identifier: MPL-2.0

from power_grid_model_io_native._core.power_grid_model_io_core import pgm_io_core
import pytest
from power_grid_model._core.error_handling import InvalidArguments

from power_grid_model_io_native._core.error_handling import assert_no_error
from power_grid_model_io_native._core.vnf_converter import PgmVnfConverter

def test_nothing():
assert pgm_io_core.error_code() == 0
assert pgm_io_core.error_message() == ""

def test_pgmvnfconverter_constructor_without_experimental_features():
"""A test case for creating pgmvnfconverter without experimental features"""
with pytest.raises(InvalidArguments):
_ = PgmVnfConverter("", 0)


def test_pgmvnfconverter_constructor_with_experimental_features():
"""A test case for creating pgmvnfconverter with experimental features"""
_ = PgmVnfConverter("", 1)
assert_no_error()


def test_get_pgm_input_data():
"""A test case for obtaining the data in PGM format from pgmvnfconverter"""
converter = PgmVnfConverter("", 1)
result_buffer = converter.get_pgm_input_data()
json_output = '{"version":"1.0","type":"input","is_batch":false,"attributes":{},"data":{}}'
assert result_buffer == json_output
Loading