diff --git a/cpp/test/generated/CMakeLists.txt b/cpp/test/generated/CMakeLists.txt index a12088c5..b7f6b753 100644 --- a/cpp/test/generated/CMakeLists.txt +++ b/cpp/test/generated/CMakeLists.txt @@ -6,7 +6,8 @@ # target_link_libraries( test_model_generated) # add_subdirectory() -find_package(date REQUIRED) +set(HOWARD_HINNANT_DATE_MINIMUM_VERSION "3.0.0") +find_package(date ${HOWARD_HINNANT_DATE_MINIMUM_VERSION} REQUIRED) if(VCPKG_TARGET_TRIPLET) set(HDF5_CXX_LIBRARIES hdf5::hdf5_cpp-shared) @@ -14,8 +15,14 @@ else() set(HDF5_CXX_LIBRARIES hdf5::hdf5_cpp) endif() -find_package(HDF5 REQUIRED COMPONENTS C CXX) -find_package(xtensor REQUIRED) +set(HDF5_MINIMUM_VERSION "1.10.5") +find_package(HDF5 ${HDF5_MINIMUM_VERSION} REQUIRED COMPONENTS C CXX) + +set(XTENSOR_MINIMUM_VERSION "0.21.10") +find_package(xtensor ${XTENSOR_MINIMUM_VERSION} REQUIRED) + +set(NLOHMANN_JSON_MINIMUM_VERSION "3.11.1") +find_package(nlohmann_json ${NLOHMANN_JSON_MINIMUM_VERSION} REQUIRED) add_library(test_model_generated OBJECT factories.cc protocols.cc @@ -31,6 +38,7 @@ target_link_libraries(test_model_generated PUBLIC ${HDF5_CXX_LIBRARIES} PUBLIC xtensor PUBLIC date::date + PUBLIC nlohmann_json::nlohmann_json ) add_library(test_model_generated_mocks OBJECT diff --git a/docs/cpp/installation.md b/docs/cpp/installation.md index 2d08af39..8764b1a6 100644 --- a/docs/cpp/installation.md +++ b/docs/cpp/installation.md @@ -7,11 +7,14 @@ In order to compile the C++ code that `yardl` generates, you will need to have a C++17 (or more recent) compiler and the following dependencies installed: -1. HDF5 with the [C++ API](https://support.hdfgroup.org/HDF5/doc/cpplus_RM/). -2. [xtensor](https://xtensor.readthedocs.io/en/latest/) +1. HDF5 with the [C++ API](https://support.hdfgroup.org/HDF5/doc/cpplus_RM/), + version 1.10.5 or later. +2. [xtensor](https://xtensor.readthedocs.io/en/latest/), version 0.21.10 or + later. 3. Howard Hinnant's [date](https://howardhinnant.github.io/date/date.html) - library. -4. [JSON for Modern C++](https://github.com/nlohmann/json). + library, version 3.0.0 or later. +4. [JSON for Modern C++](https://github.com/nlohmann/json), version: 3.11.1 or + later. ### Conda diff --git a/docs/python/quickstart.md b/docs/python/quickstart.md index 6ebf33ed..797d5c1f 100644 --- a/docs/python/quickstart.md +++ b/docs/python/quickstart.md @@ -6,7 +6,8 @@ ### Dependencies -The generated Python code requires Python 3.9 or newer and you need to have [NumPy](https://numpy.org/install/) installed. +The generated Python code requires Python 3.9 or newer and you need to have +[NumPy](https://numpy.org/install/) version 1.22.0 or later installed. ## Getting our Feet Wet diff --git a/python/test_model/__init__.py b/python/test_model/__init__.py index 854eab21..85c6b731 100644 --- a/python/test_model/__init__.py +++ b/python/test_model/__init__.py @@ -1,5 +1,22 @@ # This file was generated by the "yardl" tool. DO NOT EDIT. +from typing import Tuple as _Tuple +import re as _re +import numpy as _np + +_MIN_NUMPY_VERSION = (1, 22, 0) + +def _parse_version(version: str) -> _Tuple[int, ...]: + try: + return tuple(map(int, version.split("."))) + except ValueError: + # ignore any prerelease suffix + version = _re.sub(r"[^0-9.]", "", version) + return tuple(map(int, version.split("."))) + +if _parse_version(_np.__version__) < _MIN_NUMPY_VERSION: + raise ImportError(f"Your installed numpy version is {_np.__version__}, but version >= {'.'.join(str(i) for i in _MIN_NUMPY_VERSION)} is required.") + from .yardl_types import * from .types import ( AcquisitionOrImage, diff --git a/python/tests/roundtriputils.py b/python/tests/roundtriputils.py index 9ae11bed..905cb407 100644 --- a/python/tests/roundtriputils.py +++ b/python/tests/roundtriputils.py @@ -2,7 +2,7 @@ import pathlib import subprocess import types -from typing import Callable, TypeVar, cast +from typing import Callable, TypeVar, Union, cast import test_model as tm from .factories import Format @@ -17,8 +17,8 @@ def invoke_translator( - input: bytes | str, input_format: Format, output_format: Format -) -> bytes | str: + input: Union[bytes, str], input_format: Format, output_format: Format +) -> Union[bytes, str]: if isinstance(input, str): print(input) input = input.encode("utf-8") diff --git a/python/tests/test_init.py b/python/tests/test_init.py new file mode 100644 index 00000000..7a6acb28 --- /dev/null +++ b/python/tests/test_init.py @@ -0,0 +1,11 @@ +import test_model as tm +from packaging import version +# pyright: basic + +def test_parse_version(): + assert tm._parse_version("1.2.3") == (1,2,3) + assert tm._parse_version("1.2.3") < (1,2,4) + assert tm._parse_version("2.2.3") > (1,9,9) + assert tm._parse_version("2.2.3") > (1,9) + assert tm._parse_version("1.26.1rc1") > (1,26,1) + version.parse diff --git a/tooling/internal/cpp/cmake.go b/tooling/internal/cpp/cmake.go index 5d6999d6..a6a8092a 100644 --- a/tooling/internal/cpp/cmake.go +++ b/tooling/internal/cpp/cmake.go @@ -28,7 +28,8 @@ func writeCMakeLists(env *dsl.Environment, options packaging.CppCodegenOptions) # target_link_libraries( %s) # add_subdirectory() -find_package(date REQUIRED) +set(HOWARD_HINNANT_DATE_MINIMUM_VERSION "3.0.0") +find_package(date ${HOWARD_HINNANT_DATE_MINIMUM_VERSION} REQUIRED) if(VCPKG_TARGET_TRIPLET) set(HDF5_CXX_LIBRARIES hdf5::hdf5_cpp-shared) @@ -36,8 +37,14 @@ else() set(HDF5_CXX_LIBRARIES hdf5::hdf5_cpp) endif() -find_package(HDF5 REQUIRED COMPONENTS C CXX) -find_package(xtensor REQUIRED) +set(HDF5_MINIMUM_VERSION "1.10.5") +find_package(HDF5 ${HDF5_MINIMUM_VERSION} REQUIRED COMPONENTS C CXX) + +set(XTENSOR_MINIMUM_VERSION "0.21.10") +find_package(xtensor ${XTENSOR_MINIMUM_VERSION} REQUIRED) + +set(NLOHMANN_JSON_MINIMUM_VERSION "3.11.1") +find_package(nlohmann_json ${NLOHMANN_JSON_MINIMUM_VERSION} REQUIRED) `, objectLibraryName) fmt.Fprintf(w, "add_library(%s OBJECT\n", objectLibraryName) @@ -62,6 +69,7 @@ find_package(xtensor REQUIRED) w.WriteStringln("PUBLIC ${HDF5_CXX_LIBRARIES}") w.WriteStringln("PUBLIC xtensor") w.WriteStringln("PUBLIC date::date") + w.WriteStringln("PUBLIC nlohmann_json::nlohmann_json") }) w.WriteString(")\n") diff --git a/tooling/internal/cpp/include/detail/ndjson/serializers.h b/tooling/internal/cpp/include/detail/ndjson/serializers.h index e3700070..1bd729d3 100644 --- a/tooling/internal/cpp/include/detail/ndjson/serializers.h +++ b/tooling/internal/cpp/include/detail/ndjson/serializers.h @@ -205,8 +205,9 @@ struct adl_serializer> { static void from_json(ordered_json const& j, yardl::DynamicNDArray& value) { value.resize(j.at("shape").get>()); auto data_array = j.at("data").get>(); - for (size_t i = 0; i < data_array.size(); ++i) { - value.flat(i) = data_array[i]; + size_t i = 0; + for (auto& element : value) { + element = data_array[i++]; } } }; @@ -225,8 +226,9 @@ struct adl_serializer> { static void from_json(ordered_json const& j, yardl::NDArray& value) { value.resize(j.at("shape").get>()); auto data_array = j.at("data").get>(); - for (size_t i = 0; i < data_array.size(); ++i) { - value.flat(i) = data_array[i]; + size_t i = 0; + for (auto& element : value) { + element = data_array[i++]; } } }; @@ -243,8 +245,9 @@ struct adl_serializer> { static void from_json(ordered_json const& j, yardl::FixedNDArray& value) { auto data_array = j.get>(); - for (size_t i = 0; i < data_array.size(); ++i) { - value.flat(i) = data_array[i]; + size_t i = 0; + for (auto& element : value) { + element = data_array[i++]; } } }; diff --git a/tooling/internal/python/python.go b/tooling/internal/python/python.go index dd71e38e..e259154b 100644 --- a/tooling/internal/python/python.go +++ b/tooling/internal/python/python.go @@ -82,6 +82,24 @@ func writePackageInitFile(packageDir string, ns *dsl.Namespace) error { w := formatting.NewIndentedWriter(&b, " ") common.WriteGeneratedFileHeader(w) + w.WriteStringln(`from typing import Tuple as _Tuple +import re as _re +import numpy as _np + +_MIN_NUMPY_VERSION = (1, 22, 0) + +def _parse_version(version: str) -> _Tuple[int, ...]: + try: + return tuple(map(int, version.split("."))) + except ValueError: + # ignore any prerelease suffix + version = _re.sub(r"[^0-9.]", "", version) + return tuple(map(int, version.split("."))) + +if _parse_version(_np.__version__) < _MIN_NUMPY_VERSION: + raise ImportError(f"Your installed numpy version is {_np.__version__}, but version >= {'.'.join(str(i) for i in _MIN_NUMPY_VERSION)} is required.") +`) + fmt.Fprintf(w, "from .yardl_types import *\n") typesMembers := make([]string, 0)