diff --git a/pyproject.toml b/pyproject.toml index 35995347fc..2bb82a115b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,6 @@ test = [ "pytest-timeout", "hypothesis", "pydantic", - "typing_extensions", "resfo-utilities[testing]>=0.4.0", "numpy", "pandas", @@ -27,7 +26,6 @@ format = ["cmake-format", "clang-format", "black"] [tool.pytest.ini_options] addopts = "--strict-markers" testpaths = ["tests"] - [tool.cibuildwheel] build-frontend = "build[uv]" build = "cp311-* cp312-* cp313-* cp314-*" diff --git a/python/resdata/geometry/surface.py b/python/resdata/geometry/surface.py index 92150fb50a..0a14e59142 100644 --- a/python/resdata/geometry/surface.py +++ b/python/resdata/geometry/surface.py @@ -1,8 +1,7 @@ -from __future__ import division - """ Create a polygon """ + import os.path import ctypes diff --git a/python/resdata/grid/faults/fault_block_layer.py b/python/resdata/grid/faults/fault_block_layer.py index 1887ddea58..da8f940801 100644 --- a/python/resdata/grid/faults/fault_block_layer.py +++ b/python/resdata/grid/faults/fault_block_layer.py @@ -1,4 +1,3 @@ -from __future__ import print_function from cwrap import BaseCClass from resdata.util.util import monkey_the_camel diff --git a/python/resdata/grid/faults/fault_segments.py b/python/resdata/grid/faults/fault_segments.py index 9ef920482b..ec62287d33 100644 --- a/python/resdata/grid/faults/fault_segments.py +++ b/python/resdata/grid/faults/fault_segments.py @@ -1,5 +1,3 @@ -from __future__ import print_function - from resdata.util.util import monkey_the_camel diff --git a/python/resdata/grid/rd_grid.py b/python/resdata/grid/rd_grid.py index 49233067d6..438198c25f 100644 --- a/python/resdata/grid/rd_grid.py +++ b/python/resdata/grid/rd_grid.py @@ -18,6 +18,7 @@ import math import itertools from cwrap import CFILE, BaseCClass, load, open as copen +from typing_extensions import deprecated from resdata import ResdataPrototype from resdata.util.util import monkey_the_camel @@ -269,6 +270,10 @@ def create(cls, specgrid, zcorn, coord, actnum, mapaxes=None): ) @classmethod + @deprecated( + "Grid.createRectangular is deprecated. It will be removed in version 7. " + "Please use the similar method: GridGenerator.createRectangular.", + ) def create_rectangular(cls, dims, dV, actnum=None): """ Will create a new rectangular grid. @dims = (nx,ny,nz) @dVg = (dx,dy,dz) @@ -276,12 +281,6 @@ def create_rectangular(cls, dims, dV, actnum=None): With the default value @actnum == None all cells will be active, """ - warnings.warn( - "Grid.createRectangular is deprecated. " - + "Please use the similar method: GridGenerator.createRectangular.", - DeprecationWarning, - ) - if actnum is None: rd_grid = cls._alloc_rectangular( dims[0], dims[1], dims[2], dV[0], dV[1], dV[2], None diff --git a/python/resdata/rd_util.py b/python/resdata/rd_util.py index 50932e08f8..2cc336d0b6 100644 --- a/python/resdata/rd_util.py +++ b/python/resdata/rd_util.py @@ -10,8 +10,6 @@ functions from rd_util.c which are not bound to any class type. """ -from __future__ import absolute_import - import ctypes from cwrap import BaseCEnum diff --git a/python/resdata/resfile/rd_file.py b/python/resdata/resfile/rd_file.py index 2952c472db..9aa0e10c4c 100644 --- a/python/resdata/resfile/rd_file.py +++ b/python/resdata/resfile/rd_file.py @@ -24,6 +24,7 @@ import ctypes import datetime import re +from typing_extensions import deprecated from cwrap import BaseCClass from resdata import FileMode, FileType, ResdataPrototype @@ -575,8 +576,11 @@ def __exit__(self, exc_type, exc_val, exc_tb): return False +@deprecated( + "The function openResdataFile is deprecated, " + "and will be removed in version 7. Use open_rd_file." +) def openResdataFile(file_name, flags=FileMode.DEFAULT): - print("The function openResdataFile is deprecated, use open_rd_file.") return open_rd_file(file_name, flags) diff --git a/python/resdata/resfile/rd_file_view.py b/python/resdata/resfile/rd_file_view.py index 1544215eda..c79dd3a97b 100644 --- a/python/resdata/resfile/rd_file_view.py +++ b/python/resdata/resfile/rd_file_view.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import, division, print_function, unicode_literals from six import string_types from cwrap import BaseCClass from resdata.util.util import monkey_the_camel diff --git a/python/resdata/resfile/rd_kw.py b/python/resdata/resfile/rd_kw.py index b970ca8123..6b60bf7bee 100644 --- a/python/resdata/resfile/rd_kw.py +++ b/python/resdata/resfile/rd_kw.py @@ -25,6 +25,7 @@ import ctypes import warnings +from typing_extensions import deprecated import numpy as np from cwrap import CFILE, BaseCClass @@ -981,8 +982,10 @@ def get_min(self): return mm[0] @property + @deprecated( + "rd_kw.type is deprecated, it will be removed in version 7. Use .data_type." + ) def type(self): - warnings.warn("rd_kw.type is deprecated, use .data_type", DeprecationWarning) return self._get_type() @property @@ -992,13 +995,10 @@ def data_type(self): def type_name(self): return self.data_type.type_name + @deprecated( + "ResdataTypeEnum is deprecated. You should instead provide an ResDataType", + ) def get_rd_type(self): - warnings.warn( - "ResdataTypeEnum is deprecated. " - + "You should instead provide an ResDataType", - DeprecationWarning, - ) - return self._get_type() @property diff --git a/python/resdata/rft/rd_rft.py b/python/resdata/rft/rd_rft.py index 81881a2ef2..2d2c5c6e92 100644 --- a/python/resdata/rft/rd_rft.py +++ b/python/resdata/rft/rd_rft.py @@ -11,6 +11,7 @@ from resfo_utilities import RFTReader import fnmatch import warnings +from typing_extensions import deprecated def to_float_or_none(value: np.float32 | None) -> float | None: @@ -211,6 +212,11 @@ def category_to_type_str(s: str) -> str | None: return None +@deprecated( + "ResdataRFTFile is deprecated and will be removed in version 7, see " + "resfo-utilities.readthedocs.io/en/latest/user_guide.html" + "#module-resfo_utilities._rft_reader to migrate to resfo-utilities. ", +) class ResdataRFTFile: """Used to load an RFT file. @@ -223,12 +229,6 @@ class ResdataRFTFile: """ def __init__(self, case: str | PathLike[str]) -> None: - warnings.warn( - "ResdataRFTFile is deprecated, see " - "resfo-utilities.readthedocs.io/en/latest/user_guide.html" - "#module-resfo_utilities._rft_reader to migrate to resfo-utilities.", - DeprecationWarning, - ) try: with RFTReader.open(case) as rft: self._entries = [ diff --git a/python/resdata/summary/rd_sum.py b/python/resdata/summary/rd_sum.py index 374ffbedcb..fdba16a09a 100644 --- a/python/resdata/summary/rd_sum.py +++ b/python/resdata/summary/rd_sum.py @@ -14,6 +14,8 @@ import pandas as pd import re from typing import Sequence, List, Tuple, Optional, Union +from textwrap import dedent +from typing_extensions import deprecated # Observe that there is some convention conflict with the C code # regarding order of arguments: The C code generally takes the time @@ -397,6 +399,10 @@ def add_t_step(self, report_step, sim_days): tstep = self._add_tstep(report_step, sim_seconds).setParent(parent=self) return tstep + @deprecated( + "The method get_vector() is deprecated, and will be removed in version 7." + " Use numpy_vector() instead" + ) def get_vector(self, key, report_only=False): """ Will return SummaryVector according to @key. @@ -404,10 +410,6 @@ def get_vector(self, key, report_only=False): Will raise exception KeyError if the summary object does not have @key. """ - warnings.warn( - "The method get_vector() has been deprecated, use numpy_vector() instead", - DeprecationWarning, - ) self.assertKeyValid(key) if report_only: return SummaryVector(self, key, report_only=True) @@ -446,6 +448,10 @@ def groups(self, pattern=None): """ return self._create_group_list(pattern) + @deprecated( + "The method get_values() is deprecated, and will be removed in version 7." + " Use numpy_vector() instead." + ) def get_values(self, key, report_only=False): """ Will return numpy vector of all values according to @key. @@ -455,10 +461,6 @@ def get_values(self, key, report_only=False): also available as the 'values' property of an SummaryVector instance. """ - warnings.warn( - "The method get_values() has been deprecated - use numpy_vector() instead.", - DeprecationWarning, - ) if self.has_key(key): key_index = self._get_general_var_index(key) if report_only: @@ -800,11 +802,11 @@ def first_value(self, key): return self._get_first_value(key) + @deprecated( + "The function get_last_value() is deprecated, and will be removed in" + " version 7. Use last_value() instead" + ) def get_last_value(self, key): - warnings.warn( - "The function get_last_value() is deprecated, use last_value() instead", - DeprecationWarning, - ) return self.last_value(key) def get_last(self, key): @@ -869,37 +871,43 @@ def assert_key_valid(self, key): def __iter__(self): return iter(self.keys()) + @deprecated( + "The method the [] operator will change behaviour in version 7." + " It will then return a plain numpy vector. You are advised to change to" + " use the numpy_vector() method right away", + ) def __getitem__(self, key): """ Implements [] operator - @key should be a summary key. The returned value will be a SummaryVector instance. """ - warnings.warn( - "The method the [] operator will change behaviour in the future. It will then return a plain numpy vector. You are advised to change to use the numpy_vector() method right away", - DeprecationWarning, - ) return self.get_vector(key) def scale_vector(self, key, scalar): - msg = """The function Summary.scale_vector has been removed. As an alternative you -are advised to fetch vector as a numpy vector and then scale that yourself: + raise NotImplementedError( + dedent( + """The function Summary.scale_vector has been removed. As an alternative you + are advised to fetch vector as a numpy vector and then scale that yourself: - vec = rd_sum.numpy_vector(key) - vec *= scalar + vec = rd_sum.numpy_vector(key) + vec *= scalar - """ - raise NotImplementedError(msg) + """ + ) + ) def shift_vector(self, key, addend): - msg = """The function Summary.shift_vector has been removed. As an alternative you -are advised to fetch vector as a numpy vector and then scale that yourself: - - vec = rd_sum.numpy_vector(key) - vec += scalar - - """ - raise NotImplementedError(msg) + raise NotImplementedError( + dedent( + """The function Summary.shift_vector has been removed. As an alternative you + are advised to fetch vector as a numpy vector and then scale that yourself: + + vec = rd_sum.numpy_vector(key) + vec += scalar + """ + ) + ) def check_sim_time(self, date): """ @@ -1259,6 +1267,10 @@ def get_dates(self, report_only=False): return self.dates @property + @deprecated( + "The mpl_dates property is deprecated and will be removed in version 7." + " Use numpy_dates instead" + ) def mpl_dates(self): """ Will return a numpy vector of dates ready for matplotlib @@ -1267,12 +1279,12 @@ def mpl_dates(self): i.e. floats - generated by the date2num() function at the top of this file. """ - warnings.warn( - "The mpl_dates property has been deprecated - use numpy_dates instead", - DeprecationWarning, - ) return self.get_mpl_dates(False) + @deprecated( + "The get_mpl_dates( ) method is deprecated and will be removed in" + " version 7. Use numpy_dates instead", + ) def get_mpl_dates(self, report_only=False): """ Will return a numpy vector of dates ready for matplotlib @@ -1283,10 +1295,6 @@ def get_mpl_dates(self, report_only=False): format, i.e. floats - generated by the date2num() function at the top of this file. """ - warnings.warn( - "The get_mpl_dates( ) method has been deprecated - use numpy_dates instead", - DeprecationWarning, - ) if report_only: return [date2num(dt) for dt in self.report_dates] else: diff --git a/python/resdata/summary/rd_sum_vector.py b/python/resdata/summary/rd_sum_vector.py index 799089df7e..e84906cd81 100644 --- a/python/resdata/summary/rd_sum_vector.py +++ b/python/resdata/summary/rd_sum_vector.py @@ -1,5 +1,7 @@ -from __future__ import print_function import warnings +from typing_extensions import deprecated + + from .rd_sum_node import SummaryNode @@ -27,7 +29,7 @@ def __init__(self, parent, key, report_only=False): if report_only: warnings.warn( - "The report_only flag to the SummaryVector will be removed", + "The report_only flag to the SummaryVector will be removed in version 7.", DeprecationWarning, ) @@ -88,6 +90,10 @@ def days(self): return self.__days @property + @deprecated( + "The mpl_dates property has been deprecated, and will be " + "removed in version 7. Use numpy_dates instead" + ) def mpl_dates(self): """ All the dates as numpy vector of dates in matplotlib format. @@ -95,11 +101,6 @@ def mpl_dates(self): backwards-compatibility for the time-being. Usage will trigger a depreciation warning. """ - warnings.warn( - "The mpl_dates property has been deprecated - use numpy_dates instead", - DeprecationWarning, - ) - return self.parent.get_mpl_dates(self.report_only) @property diff --git a/python/resdata/util/test/debug_msg.py b/python/resdata/util/test/debug_msg.py index 9faac85ec1..fe348c88f6 100644 --- a/python/resdata/util/test/debug_msg.py +++ b/python/resdata/util/test/debug_msg.py @@ -1,6 +1,8 @@ import inspect +from typing_extensions import deprecated +@deprecated("debug_msg is deprecated and will be removed in version 7") def debug_msg(msg): record = inspect.stack()[1] frame = record[0] diff --git a/python/resdata/util/test/extended_testcase.py b/python/resdata/util/test/extended_testcase.py index 26c7ae218c..df01053d6a 100644 --- a/python/resdata/util/test/extended_testcase.py +++ b/python/resdata/util/test/extended_testcase.py @@ -3,6 +3,7 @@ import os.path import traceback import sys +from typing_extensions import deprecated try: from unittest2 import TestCase @@ -20,6 +21,7 @@ # or lock up. +@deprecated("resdata.util.test is deprecated and will be removed in version 7") def log_test(test): def wrapper(*args): sys.stderr.write("starting: %s \n" % test.__name__) @@ -29,6 +31,7 @@ def wrapper(*args): return wrapper +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class _AssertNotRaisesContext(object): def __init__(self, test_class): super(_AssertNotRaisesContext, self).__init__() @@ -50,12 +53,12 @@ def __exit__(self, exc_type, exc_value, tb): return True -""" -This class provides some extra functionality for testing values that are almost equal. -""" - - +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class ExtendedTestCase(TestCase): + """ + This class provides some extra functionality for testing values that are almost equal. + """ + TESTDATA_ROOT = None SHARE_ROOT = None SOURCE_ROOT = None diff --git a/python/resdata/util/test/import_test_case.py b/python/resdata/util/test/import_test_case.py index 3d00689d9a..7d3f9ff0cb 100644 --- a/python/resdata/util/test/import_test_case.py +++ b/python/resdata/util/test/import_test_case.py @@ -2,8 +2,10 @@ import inspect import os import unittest +from typing_extensions import deprecated +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class ImportTestCase(unittest.TestCase): def import_module(self, module): return importlib.import_module(module) diff --git a/python/resdata/util/test/lint_test_case.py b/python/resdata/util/test/lint_test_case.py index f743fcde13..41cf7e179a 100644 --- a/python/resdata/util/test/lint_test_case.py +++ b/python/resdata/util/test/lint_test_case.py @@ -3,6 +3,7 @@ import fnmatch import os import unittest +from typing_extensions import deprecated try: from pylint import epylint as lint @@ -13,6 +14,7 @@ lint = None +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class LintTestCase(unittest.TestCase): """This class is a test case for linting.""" diff --git a/python/resdata/util/test/mock/rd_sum_mock.py b/python/resdata/util/test/mock/rd_sum_mock.py index d120ecfd9f..b8ea98d390 100644 --- a/python/resdata/util/test/mock/rd_sum_mock.py +++ b/python/resdata/util/test/mock/rd_sum_mock.py @@ -1,11 +1,14 @@ import datetime from resdata.summary import Summary +from typing_extensions import deprecated +@deprecated("resdata.util.test is deprecated and will be removed in version 7") def mock_func(rd_sum, key, days): return days * 10 +@deprecated("resdata.util.test is deprecated and will be removed in version 7") def createSummary( case, keys, diff --git a/python/resdata/util/test/path_context.py b/python/resdata/util/test/path_context.py index d042f1d012..4c5b31efea 100644 --- a/python/resdata/util/test/path_context.py +++ b/python/resdata/util/test/path_context.py @@ -1,7 +1,9 @@ import os import shutil +from typing_extensions import deprecated +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class PathContext(object): def __init__(self, path, store=False): self.path = path diff --git a/python/resdata/util/test/resdata_test_runner.py b/python/resdata/util/test/resdata_test_runner.py index d6e0c60e62..5ba6d8aeb5 100644 --- a/python/resdata/util/test/resdata_test_runner.py +++ b/python/resdata/util/test/resdata_test_runner.py @@ -1,4 +1,5 @@ import os +from typing_extensions import deprecated try: from unittest2 import TestLoader, TextTestRunner @@ -6,6 +7,7 @@ from unittest import TestLoader, TextTestRunner +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class ResdataTestRunner(object): @staticmethod def runTestSuite(tests, test_verbosity=3): diff --git a/python/resdata/util/test/source_enumerator.py b/python/resdata/util/test/source_enumerator.py index aca52b04a0..6852bb0835 100644 --- a/python/resdata/util/test/source_enumerator.py +++ b/python/resdata/util/test/source_enumerator.py @@ -1,7 +1,9 @@ import os import re +from typing_extensions import deprecated +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class SourceEnumerator(object): @classmethod def removeComments(cls, code_string): diff --git a/python/resdata/util/test/test_area.py b/python/resdata/util/test/test_area.py index 29c75c0c20..3d382169e1 100644 --- a/python/resdata/util/test/test_area.py +++ b/python/resdata/util/test/test_area.py @@ -2,8 +2,10 @@ from cwrap import BaseCClass from resdata import ResdataPrototype +from typing_extensions import deprecated +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class TestArea(BaseCClass): __test__ = False diff --git a/python/resdata/util/test/test_run.py b/python/resdata/util/test/test_run.py index 59fad8ffe6..aed1c9f77f 100644 --- a/python/resdata/util/test/test_run.py +++ b/python/resdata/util/test/test_run.py @@ -2,9 +2,12 @@ import os.path import subprocess import argparse +from typing_extensions import deprecated + from .test_area import TestAreaContext +@deprecated("resdata.util.test is deprecated and will be removed in version 7") def path_exists(path): if os.path.exists(path): return (True, "Path:%s exists" % path) @@ -12,6 +15,7 @@ def path_exists(path): return (False, "ERROR: Path:%s does not exist" % path) +@deprecated("resdata.util.test is deprecated and will be removed in version 7") class TestRun(object): default_ert_cmd = "ert" default_ert_version = "stable" diff --git a/python/resdata/util/util/__init__.py b/python/resdata/util/util/__init__.py index 5ee33d9b9e..7b45b5b6cc 100644 --- a/python/resdata/util/util/__init__.py +++ b/python/resdata/util/util/__init__.py @@ -21,8 +21,6 @@ """ -from __future__ import absolute_import, division, print_function, unicode_literals - import resdata from cwrap import Prototype @@ -56,10 +54,9 @@ ### usage. ### -import os import warnings -__cc = os.environ.get("RDWARNING", None) # __cc in (None, 'user', 'dev', 'hard') +__cc = "dev" def __silencio(msg): @@ -98,7 +95,8 @@ def shift(*args): def warned_method(*args, **kwargs): __rd_camel_case_warning( - "Warning, %s is deprecated, use %s" % (camel, str(method_)) + f"Warning, {camel} is deprecated. It will be removed in version 7." + f" Use {str(method_)}" ) return method_(*shift(*args), **kwargs) diff --git a/python/resdata/util/util/lookup_table.py b/python/resdata/util/util/lookup_table.py index a1c6a4e2cc..6946080090 100644 --- a/python/resdata/util/util/lookup_table.py +++ b/python/resdata/util/util/lookup_table.py @@ -64,7 +64,6 @@ def __len__(self): def size(self): return len(self) - # Deprecated properties @property def max(self): return self.getMaxValue() diff --git a/python/resdata/util/util/vector_template.py b/python/resdata/util/util/vector_template.py index a487c2fda5..522a8cd83c 100644 --- a/python/resdata/util/util/vector_template.py +++ b/python/resdata/util/util/vector_template.py @@ -25,8 +25,6 @@ float and size_t not currently implemented in the Python version. """ -from __future__ import absolute_import, division, print_function, unicode_literals - import sys from cwrap import CFILE, BaseCClass diff --git a/setup.py b/setup.py index f834d37722..f1497972bb 100644 --- a/setup.py +++ b/setup.py @@ -148,6 +148,7 @@ def utility_wrappers(): "numpy", "pandas", "natsort", + "typing_extensions", "resfo-utilities>=0.4.0", ], setup_requires=["conan>=2"], diff --git a/tests/__init__.py b/tests/__init__.py index 709e3de3f5..692777e1c9 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,11 +1,12 @@ import os.path import types -from resdata.util.test import ExtendedTestCase from functools import wraps from functools import partial import unittest from unittest import SkipTest +from .util import ExtendedTestCase + def source_root(): src = "@CMAKE_CURRENT_SOURCE_DIR@/../.." diff --git a/tests/bin_tests/test_summary_resample.py b/tests/bin_tests/test_summary_resample.py index fbc873c0e5..9f52e28130 100644 --- a/tests/bin_tests/test_summary_resample.py +++ b/tests/bin_tests/test_summary_resample.py @@ -4,10 +4,10 @@ from resdata.grid import Cell, Grid from resdata.summary import Summary -from resdata.util.test import TestAreaContext -from resdata.util.test.mock import createSummary from tests import ResdataTest +from tests.util import TestAreaContext +from tests.util.mock import createSummary def fopr(days): diff --git a/tests/conftest.py b/tests/conftest.py index 66f07a68f4..1da6240edb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,7 @@ from hypothesis import HealthCheck, settings +import os import pytest +from unittest.mock import patch # Timeout settings are unreliable both on CI and # when running pytest with xdist so we disable it diff --git a/tests/geometry_tests/test_cpolyline.py b/tests/geometry_tests/test_cpolyline.py index 72630fdc0a..8bc4e23603 100644 --- a/tests/geometry_tests/test_cpolyline.py +++ b/tests/geometry_tests/test_cpolyline.py @@ -2,8 +2,8 @@ from resdata.geometry import CPolyline, Polyline from resdata.geometry.xyz_io import XYZIo -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class CPolylineTest(ResdataTest): diff --git a/tests/geometry_tests/test_cpolyline_collection.py b/tests/geometry_tests/test_cpolyline_collection.py index 037ddc2291..efdb2c0cc8 100644 --- a/tests/geometry_tests/test_cpolyline_collection.py +++ b/tests/geometry_tests/test_cpolyline_collection.py @@ -2,9 +2,9 @@ from resdata.geometry import CPolylineCollection, CPolyline from resdata.geometry.xyz_io import XYZIo -from resdata.util.test import TestAreaContext -from tests import ResdataTest from resdata.util.util import DoubleVector +from tests import ResdataTest +from tests.util import TestAreaContext class CPolylineCollectionTest(ResdataTest): diff --git a/tests/geometry_tests/test_geo_pointset.py b/tests/geometry_tests/test_geo_pointset.py index 49da256639..ba1ccefe25 100644 --- a/tests/geometry_tests/test_geo_pointset.py +++ b/tests/geometry_tests/test_geo_pointset.py @@ -1,6 +1,6 @@ from resdata.geometry import GeoPointset, Surface -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class GeoPointsetTest(ResdataTest): diff --git a/tests/geometry_tests/test_geo_region.py b/tests/geometry_tests/test_geo_region.py index cfcc12ee21..fa0a4d4cce 100644 --- a/tests/geometry_tests/test_geo_region.py +++ b/tests/geometry_tests/test_geo_region.py @@ -1,6 +1,6 @@ from resdata.geometry import GeoRegion, GeoPointset, CPolyline, Surface -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class GeoRegionTest(ResdataTest): diff --git a/tests/geometry_tests/test_geometry_tools.py b/tests/geometry_tests/test_geometry_tools.py index 7c72edad78..32d399caf6 100644 --- a/tests/geometry_tests/test_geometry_tools.py +++ b/tests/geometry_tests/test_geometry_tools.py @@ -2,8 +2,8 @@ from resdata.geometry import Polyline, GeometryTools, CPolyline from resdata.geometry.xyz_io import XYZIo -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class GeometryToolsTest(ResdataTest): diff --git a/tests/geometry_tests/test_polyline.py b/tests/geometry_tests/test_polyline.py index 77a8baa6f5..c96e99fc8e 100644 --- a/tests/geometry_tests/test_polyline.py +++ b/tests/geometry_tests/test_polyline.py @@ -1,7 +1,7 @@ from resdata.geometry import Polyline, GeometryTools from resdata.geometry.xyz_io import XYZIo -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class PolylineTest(ResdataTest): diff --git a/tests/geometry_tests/test_surface.py b/tests/geometry_tests/test_surface.py index e23691a073..6dc63c5179 100644 --- a/tests/geometry_tests/test_surface.py +++ b/tests/geometry_tests/test_surface.py @@ -1,7 +1,7 @@ import random from resdata.geometry import Surface -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class SurfaceTest(ResdataTest): diff --git a/tests/rd_tests/test_debug.py b/tests/rd_tests/test_debug.py deleted file mode 100644 index d836cf296e..0000000000 --- a/tests/rd_tests/test_debug.py +++ /dev/null @@ -1,9 +0,0 @@ -from resdata.util.test import debug_msg -from tests import ResdataTest - - -class DebugTest(ResdataTest): - def test_create(self): - msg = debug_msg("DEBUG") - self.assertIn(__file__[:-1], msg) - self.assertIn("DEBUG", msg) diff --git a/tests/rd_tests/test_deprecation.py b/tests/rd_tests/test_deprecation.py index d754f1b5ff..7501118323 100644 --- a/tests/rd_tests/test_deprecation.py +++ b/tests/rd_tests/test_deprecation.py @@ -7,10 +7,11 @@ from resdata.grid import Grid, GridGenerator, ResdataRegion from resdata.resfile import FortIO, ResdataFile, ResdataKW, openFortIO from resdata.rft import ResdataRFT -from resdata.util.test import TestAreaContext -from resdata.util.test.mock import createSummary from resdata.util.util import BoolVector + from tests import ResdataTest +from tests.util import TestAreaContext +from tests.util.mock import createSummary # The class Deprecation_1_9_Test contains methods which will be marked # as deprecated in the 1.9.x versions. diff --git a/tests/rd_tests/test_fault_blocks.py b/tests/rd_tests/test_fault_blocks.py index 69f4d2d8b0..0bd5dd5daa 100644 --- a/tests/rd_tests/test_fault_blocks.py +++ b/tests/rd_tests/test_fault_blocks.py @@ -7,8 +7,8 @@ from resdata.grid import Grid, ResdataRegion, GridGenerator from resdata.grid.faults import FaultBlock, FaultBlockLayer, FaultCollection from resdata.geometry import Polyline, CPolylineCollection -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext import gc diff --git a/tests/rd_tests/test_faults.py b/tests/rd_tests/test_faults.py index 8bab74756d..c096a61e99 100644 --- a/tests/rd_tests/test_faults.py +++ b/tests/rd_tests/test_faults.py @@ -14,9 +14,9 @@ FaultBlockLayer, SegmentMap, ) -from resdata.util.test import TestAreaContext from resdata.geometry import Polyline, CPolyline from tests import ResdataTest +from tests.util import TestAreaContext class FaultTest(ResdataTest): diff --git a/tests/rd_tests/test_fk_user_data.py b/tests/rd_tests/test_fk_user_data.py index f468cc71df..ad5c40cac2 100644 --- a/tests/rd_tests/test_fk_user_data.py +++ b/tests/rd_tests/test_fk_user_data.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from resdata.grid import Grid -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class FKTest(ResdataTest): diff --git a/tests/rd_tests/test_fortio.py b/tests/rd_tests/test_fortio.py index e2161a0df9..de9e18a9cd 100755 --- a/tests/rd_tests/test_fortio.py +++ b/tests/rd_tests/test_fortio.py @@ -4,8 +4,8 @@ from random import randint from resdata import ResDataType from resdata.resfile import FortIO, ResdataKW, openFortIO, ResdataFile -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class FortIOTest(ResdataTest): diff --git a/tests/rd_tests/test_geertsma.py b/tests/rd_tests/test_geertsma.py index 73b2e6a576..40973d88e2 100644 --- a/tests/rd_tests/test_geertsma.py +++ b/tests/rd_tests/test_geertsma.py @@ -5,8 +5,8 @@ from resdata.grid import GridGenerator from resdata.gravimetry import ResdataSubsidence -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext from .create_restart import create_restart import numpy as np diff --git a/tests/rd_tests/test_grav.py b/tests/rd_tests/test_grav.py index a4b58cacaa..e36b4df35b 100644 --- a/tests/rd_tests/test_grav.py +++ b/tests/rd_tests/test_grav.py @@ -3,8 +3,9 @@ from resdata.resfile import ResdataKW, ResdataFile, openFortIO, FortIO from resdata.grid import GridGenerator from resdata.gravimetry import ResdataGrav -from resdata.util.test import TestAreaContext + from tests import ResdataTest +from tests.util import TestAreaContext def write_kws(filename, kws): diff --git a/tests/rd_tests/test_grid.py b/tests/rd_tests/test_grid.py index f8e9db657e..3468a71341 100644 --- a/tests/rd_tests/test_grid.py +++ b/tests/rd_tests/test_grid.py @@ -13,8 +13,9 @@ from resdata.resfile import ResdataKW, ResdataFile from resdata.grid import Grid from resdata.grid import GridGenerator as GridGen -from resdata.util.test import TestAreaContext + from tests import ResdataTest +from tests.util import TestAreaContext # This dict is used to verify that corners are mapped to the correct # cell with respect to containment. diff --git a/tests/rd_tests/test_grid_equinor.py b/tests/rd_tests/test_grid_equinor.py index c0a01f4743..7e444c9d4e 100755 --- a/tests/rd_tests/test_grid_equinor.py +++ b/tests/rd_tests/test_grid_equinor.py @@ -14,8 +14,9 @@ from resdata.resfile import ResdataKW, ResdataFile, openResdataFile from resdata.grid import Grid, GridGenerator from resdata.util.util import DoubleVector, IntVector -from resdata.util.test import TestAreaContext + from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext @equinor_test() diff --git a/tests/rd_tests/test_grid_equinor_coarse.py b/tests/rd_tests/test_grid_equinor_coarse.py index 7c63731052..136d3aef8c 100644 --- a/tests/rd_tests/test_grid_equinor_coarse.py +++ b/tests/rd_tests/test_grid_equinor_coarse.py @@ -2,8 +2,9 @@ from resdata.resfile import ResdataRestartFile from resdata.grid import Grid -from resdata.util.test import TestAreaContext + from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext @equinor_test() diff --git a/tests/rd_tests/test_grid_equinor_dual.py b/tests/rd_tests/test_grid_equinor_dual.py index 731abd31f3..1978774605 100644 --- a/tests/rd_tests/test_grid_equinor_dual.py +++ b/tests/rd_tests/test_grid_equinor_dual.py @@ -1,9 +1,9 @@ import math -from resdata.util.test import TestAreaContext from resdata.grid import Grid from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext @equinor_test() diff --git a/tests/rd_tests/test_grid_generator.py b/tests/rd_tests/test_grid_generator.py index 54343bc2e0..5e742f3520 100644 --- a/tests/rd_tests/test_grid_generator.py +++ b/tests/rd_tests/test_grid_generator.py @@ -9,8 +9,9 @@ from resdata.resfile import ResdataKW from resdata.grid import Grid from resdata.grid import GridGenerator as GridGen -from resdata.util.test import TestAreaContext + from tests import ResdataTest +from tests.util import TestAreaContext def generate_ijk_bounds(dims): diff --git a/tests/rd_tests/test_layer.py b/tests/rd_tests/test_layer.py index 6aa29646e7..8717007cd7 100644 --- a/tests/rd_tests/test_layer.py +++ b/tests/rd_tests/test_layer.py @@ -6,8 +6,8 @@ from resdata.grid import GridGenerator from resdata.geometry import CPolyline from resdata.grid.faults import Layer, FaultCollection -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class LayerTest(ResdataTest): diff --git a/tests/rd_tests/test_npv.py b/tests/rd_tests/test_npv.py index 4c7394de0f..9fc3dbfce0 100644 --- a/tests/rd_tests/test_npv.py +++ b/tests/rd_tests/test_npv.py @@ -10,10 +10,10 @@ from resdata.summary import Summary from resdata.summary import ResdataNPV, NPVPriceVector - from resdata.util.util import StringList, TimeVector, DoubleVector, CTime -from resdata.util.test import TestAreaContext + from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext base = "ECLIPSE" path = "Equinor/ECLIPSE/Gurbat" diff --git a/tests/rd_tests/test_rd_3dkw.py b/tests/rd_tests/test_rd_3dkw.py index fde9e9fb44..eb759b7a38 100644 --- a/tests/rd_tests/test_rd_3dkw.py +++ b/tests/rd_tests/test_rd_3dkw.py @@ -6,8 +6,9 @@ from resdata import ResDataType, FileMode from resdata.resfile import Resdata3DKW, ResdataKW, ResdataFile, FortIO from resdata.grid import GridGenerator -from resdata.util.test import TestAreaContext + from tests import ResdataTest +from tests.util import TestAreaContext class Resdata3DKWTest(ResdataTest): diff --git a/tests/rd_tests/test_rd_cmp.py b/tests/rd_tests/test_rd_cmp.py index 13f1d20299..91fe58e1ab 100644 --- a/tests/rd_tests/test_rd_cmp.py +++ b/tests/rd_tests/test_rd_cmp.py @@ -1,7 +1,7 @@ from resdata.summary import ResdataCmp -from resdata.util.test import TestAreaContext -from resdata.util.test.mock import createSummary from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext +from tests.util.mock import createSummary @equinor_test() diff --git a/tests/rd_tests/test_rd_file.py b/tests/rd_tests/test_rd_file.py index 459bf8c8ca..4538381559 100644 --- a/tests/rd_tests/test_rd_file.py +++ b/tests/rd_tests/test_rd_file.py @@ -7,9 +7,11 @@ from resdata import FileMode, ResDataType, FileType from resdata.resfile import ResdataFile, FortIO, ResdataKW, openFortIO, openResdataFile from resdata.util.util import CWDContext -from resdata.util.test import TestAreaContext from resdata.grid import Grid + from tests import ResdataTest +from tests.util import TestAreaContext + from .create_restart import create_restart diff --git a/tests/rd_tests/test_rd_file_equinor.py b/tests/rd_tests/test_rd_file_equinor.py index a374b51493..d8e73d8994 100755 --- a/tests/rd_tests/test_rd_file_equinor.py +++ b/tests/rd_tests/test_rd_file_equinor.py @@ -6,8 +6,8 @@ from resdata import FileMode, FileType from resdata.resfile import ResdataFile, FortIO, ResdataKW, openFortIO, openResdataFile -from resdata.util.test import TestAreaContext from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext @equinor_test() @@ -462,7 +462,7 @@ def test_ix_case(self): "WWCT", ] - padd = lambda str_len: (lambda s: s + (" " * (max(0, str_len - len(s))))) + padd = lambda str_len: lambda s: s + (" " * (max(0, str_len - len(s)))) self.assertEqual(list(map(padd(8), keywords_from_file)), keywords_loaded) # Names diff --git a/tests/rd_tests/test_rd_kw.py b/tests/rd_tests/test_rd_kw.py index ab3d283c16..01a7245779 100644 --- a/tests/rd_tests/test_rd_kw.py +++ b/tests/rd_tests/test_rd_kw.py @@ -12,8 +12,8 @@ from resdata.resfile import ResdataKW, ResdataFile, FortIO, openFortIO -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext def copy_long(): diff --git a/tests/rd_tests/test_rd_kw_equinor.py b/tests/rd_tests/test_rd_kw_equinor.py index 12afd83cb8..292785cca6 100755 --- a/tests/rd_tests/test_rd_kw_equinor.py +++ b/tests/rd_tests/test_rd_kw_equinor.py @@ -4,8 +4,8 @@ from resdata import ResDataType, FileMode from resdata.resfile import ResdataKW, ResdataFile, FortIO -from resdata.util.test import TestAreaContext from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext def copy_long(): diff --git a/tests/rd_tests/test_rd_sum.py b/tests/rd_tests/test_rd_sum.py index dac7d77606..06a54237c0 100644 --- a/tests/rd_tests/test_rd_sum.py +++ b/tests/rd_tests/test_rd_sum.py @@ -11,9 +11,9 @@ from resdata.resfile import FortIO, ResdataKW, openFortIO, openResdataFile from resdata.summary import Summary, SummaryKeyWordVector from resdata.summary.rd_sum import date2num -from resdata.util.test import TestAreaContext from resdata.util.util import TimeVector, DoubleVector, StringList from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext from resfo_utilities.testing import ( summaries, Unsmry, diff --git a/tests/rd_tests/test_rd_type.py b/tests/rd_tests/test_rd_type.py index adad89d9ae..24b06cd54b 100644 --- a/tests/rd_tests/test_rd_type.py +++ b/tests/rd_tests/test_rd_type.py @@ -1,8 +1,8 @@ -from resdata.util.test import TestAreaContext -from tests import ResdataTest - from resdata import ResDataType, ResdataTypeEnum +from tests import ResdataTest +from tests.util import TestAreaContext + def get_const_size_types(): return ResdataTypeEnum.enums()[:-1:] diff --git a/tests/rd_tests/test_rft_equinor.py b/tests/rd_tests/test_rft_equinor.py index ef76a3738c..e1c39ebe94 100644 --- a/tests/rd_tests/test_rft_equinor.py +++ b/tests/rd_tests/test_rft_equinor.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python -from __future__ import print_function import datetime from resdata.rft import ResdataRFTFile, ResdataRFTCell, ResdataPLTCell, WellTrajectory from tests import ResdataTest, equinor_test diff --git a/tests/rd_tests/test_sum.py b/tests/rd_tests/test_sum.py index d0213b87e8..34b9ef4d1c 100644 --- a/tests/rd_tests/test_sum.py +++ b/tests/rd_tests/test_sum.py @@ -25,10 +25,11 @@ def assert_frame_equal(a, b): from resdata import ResDataType, UnitSystem from resdata.resfile import FortIO, ResdataFile, ResdataKW, openFortIO from resdata.summary import Summary, SummaryKeyWordVector, SummaryVarType -from resdata.util.test import TestAreaContext -from resdata.util.test.mock import createSummary from resdata.util.util import CTime, TimeVector + from tests import ResdataTest +from tests.util import TestAreaContext +from tests.util.mock import createSummary @contextmanager diff --git a/tests/rd_tests/test_sum_equinor.py b/tests/rd_tests/test_sum_equinor.py index 0f46400dd3..ff6b69772f 100755 --- a/tests/rd_tests/test_sum_equinor.py +++ b/tests/rd_tests/test_sum_equinor.py @@ -9,8 +9,8 @@ from resdata.util.util import StringList, TimeVector, DoubleVector, CTime -from resdata.util.test import TestAreaContext from tests import ResdataTest, equinor_test +from tests.util import TestAreaContext import csv base = "ECLIPSE" diff --git a/tests/util/__init__.py b/tests/util/__init__.py new file mode 100644 index 0000000000..61273768f1 --- /dev/null +++ b/tests/util/__init__.py @@ -0,0 +1,2 @@ +from .extended_testcase import ExtendedTestCase +from .test_area import TestArea, TestAreaContext diff --git a/tests/util/extended_testcase.py b/tests/util/extended_testcase.py new file mode 100644 index 0000000000..b285d6b898 --- /dev/null +++ b/tests/util/extended_testcase.py @@ -0,0 +1,202 @@ +import numbers +import os +import os.path +import traceback +import sys + +try: + from unittest2 import TestCase +except ImportError: + from unittest import TestCase + +from .source_enumerator import SourceEnumerator +from resdata.util.util import installAbortSignals +from resdata.util.util import Version + +# Function wrapper which can be used to add decorator @log_test to test +# methods. When a test has been decorated with @log_test it will print +# "starting: " when a method is complete and "complete: " +# when the method is complete. Convenient when debugging tests which fail hard +# or lock up. + + +def log_test(test): + def wrapper(*args): + sys.stderr.write("starting: %s \n" % test.__name__) + test(*args) + sys.stderr.write("complete: %s \n" % test.__name__) + + return wrapper + + +class _AssertNotRaisesContext(object): + def __init__(self, test_class): + super(_AssertNotRaisesContext, self).__init__() + self._test_class = test_class + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_type is not None: + try: + exc_name = exc_type.__name__ + except AttributeError: + exc_name = str(exc_type) + self._test_class.fail( + "Exception: %s raised\n%s" + % (exc_name, traceback.print_exception(exc_type, exc_value, tb)) + ) + return True + + +class ExtendedTestCase(TestCase): + """ + This class provides some extra functionality for testing values that are almost equal. + """ + + TESTDATA_ROOT = None + SHARE_ROOT = None + SOURCE_ROOT = None + + def __init__(self, *args, **kwargs): + installAbortSignals() + super(ExtendedTestCase, self).__init__(*args, **kwargs) + + def assertFloatEqual(self, first, second, msg=None, tolerance=1e-6): + try: + f_first, f_second = float(first), float(second) + diff = abs(f_first - f_second) + scale = max(1, abs(first) + abs(second)) + if msg is None: + msg = "Floats not equal: |%f - %f| > %g" % ( + f_first, + f_second, + tolerance, + ) + self.assertTrue(diff < tolerance * scale, msg=msg) + except TypeError: + self.fail( + "Cannot compare as floats: %s (%s) and %s (%s)" + % (first, type(first), second, type(second)) + ) + + def assertAlmostEqualList(self, first, second, msg=None, tolerance=1e-6): + if len(first) != len(second): + self.fail("Lists are not of same length!") + + for index in range(len(first)): + self.assertFloatEqual( + first[index], second[index], msg=msg, tolerance=tolerance + ) + + def assertImportable(self, module_name): + try: + __import__(module_name) + except ImportError: + tb = traceback.format_exc() + self.fail("Module %s not found!\n\nTrace:\n%s" % (module_name, str(tb))) + except Exception: + tb = traceback.format_exc() + self.fail( + "Import of module %s caused errors!\n\nTrace:\n%s" + % (module_name, str(tb)) + ) + + def assertFilesAreEqual(self, first, second): + if not self.__filesAreEqual(first, second): + self.fail("Buffer contents of files are not identical!") + + def assertFilesAreNotEqual(self, first, second): + if self.__filesAreEqual(first, second): + self.fail("Buffer contents of files are identical!") + + def assertFileExists(self, path): + if not os.path.exists(path) or not os.path.isfile(path): + self.fail("The file: %s does not exist!" % path) + + def assertDirectoryExists(self, path): + if not os.path.exists(path) or not os.path.isdir(path): + self.fail("The directory: %s does not exist!" % path) + + def assertFileDoesNotExist(self, path): + if os.path.exists(path) and os.path.isfile(path): + self.fail("The file: %s exists!" % path) + + def assertDirectoryDoesNotExist(self, path): + if os.path.exists(path) and os.path.isdir(path): + self.fail("The directory: %s exists!" % path) + + def __filesAreEqual(self, first, second): + buffer1 = open(first, "rb").read() + buffer2 = open(second, "rb").read() + + return buffer1 == buffer2 + + def assertEnumIsFullyDefined( + self, enum_class, enum_name, source_path, verbose=False + ): + if self.SOURCE_ROOT is None: + raise Exception("SOURCE_ROOT is not set.") + + enum_values = SourceEnumerator.findEnumerators( + enum_name, os.path.join(self.SOURCE_ROOT, source_path) + ) + + for identifier, value in enum_values: + if verbose: + print("%s = %d" % (identifier, value)) + + self.assertTrue( + identifier in enum_class.__dict__, + "Enum does not have identifier: %s" % identifier, + ) + class_value = enum_class.__dict__[identifier] + self.assertEqual( + class_value, + value, + "Enum value for identifier: %s does not match: %s != %s" + % (identifier, class_value, value), + ) + + @classmethod + def createSharePath(cls, path): + if cls.SHARE_ROOT is None: + raise Exception( + "Trying to create directory rooted in 'SHARE_ROOT' - variable 'SHARE_ROOT' is not set." + ) + return os.path.realpath(os.path.join(cls.SHARE_ROOT, path)) + + @classmethod + def createTestPath(cls, path): + if cls.TESTDATA_ROOT is None: + raise Exception( + "Trying to create directory rooted in 'TESTDATA_ROOT' - variable 'TESTDATA_ROOT' has not been set." + ) + return os.path.realpath(os.path.join(cls.TESTDATA_ROOT, path)) + + def assertNotRaises(self, func=None): + context = _AssertNotRaisesContext(self) + if func is None: + return context + + with context: + func() + + @staticmethod + def slowTestShouldNotRun(): + """ + @param: The slow test flag can be set by environment variable SKIP_SLOW_TESTS = [True|False] + """ + + return os.environ.get("SKIP_SLOW_TESTS", "False") == "True" + + @staticmethod + def requireVersion(major, minor, micro="git"): + required_version = Version(major, minor, micro) + current_version = Version.currentVersion() + + if required_version < current_version: + return True + else: + return False diff --git a/tests/util/mock/__init__.py b/tests/util/mock/__init__.py new file mode 100644 index 0000000000..01d5fc1ea1 --- /dev/null +++ b/tests/util/mock/__init__.py @@ -0,0 +1 @@ +from .rd_sum_mock import createSummary diff --git a/tests/util/mock/rd_sum_mock.py b/tests/util/mock/rd_sum_mock.py new file mode 100644 index 0000000000..d120ecfd9f --- /dev/null +++ b/tests/util/mock/rd_sum_mock.py @@ -0,0 +1,66 @@ +import datetime +from resdata.summary import Summary + + +def mock_func(rd_sum, key, days): + return days * 10 + + +def createSummary( + case, + keys, + sim_start=datetime.date(2010, 1, 1), + data_start=None, + sim_length_days=5 * 365, + num_report_step=5, + num_mini_step=10, + dims=(20, 10, 5), + func_table={}, + restart_case=None, + restart_step=-1, +): + rd_sum = Summary.restart_writer( + case, restart_case, restart_step, sim_start, dims[0], dims[1], dims[2] + ) + var_list = [] + for kw, wgname, num, unit in keys: + var_list.append(rd_sum.addVariable(kw, wgname=wgname, num=num, unit=unit)) + + # This is a bug! This should not be integer division, but tests are written + # around that assumption. + report_step_length = ( + 0.0 if num_report_step == 0 else float(sim_length_days // num_report_step) + ) + mini_step_length = ( + 0.0 if num_mini_step == 0 else float(report_step_length // num_mini_step) + ) + + if data_start is None: + time_offset = 0 + else: + dt = data_start - sim_start + time_offset = dt.total_seconds() / 86400.0 + + for report_step in range(num_report_step): + for mini_step in range(num_mini_step): + days = ( + time_offset + + report_step * report_step_length + + mini_step * mini_step_length + ) + t_step = rd_sum.addTStep(report_step + 1, sim_days=days) + + for var in var_list: + key = var.getKey1() + key2 = var.getKey2() + if key and key2: + assert var.keyword in key + assert var.keyword in key2 + + if key in func_table: + func = func_table[key] + t_step[key] = func(days) + else: + t_step[key] = mock_func(rd_sum, key, days) + + return rd_sum diff --git a/tests/util/source_enumerator.py b/tests/util/source_enumerator.py new file mode 100644 index 0000000000..aca52b04a0 --- /dev/null +++ b/tests/util/source_enumerator.py @@ -0,0 +1,41 @@ +import os +import re + + +class SourceEnumerator(object): + @classmethod + def removeComments(cls, code_string): + code_string = re.sub( + re.compile(r"/\*.*?\*/", re.DOTALL), "", code_string + ) # remove all occurance streamed comments (/*COMMENT */) from string + code_string = re.sub( + re.compile("//.*?\n"), "", code_string + ) # remove all occurance singleline comments (//COMMENT\n ) from string + return code_string + + @classmethod + def findEnum(cls, enum_name, full_source_file_path): + with open(full_source_file_path, "r") as f: + text = f.read() + + text = SourceEnumerator.removeComments(text) + + enum_pattern = re.compile(r"typedef\s+enum\s+\{(.*?)\}\s*(\w+?);", re.DOTALL) + + for enum in enum_pattern.findall(text): + if enum[1] == enum_name: + return enum[0] + + raise ValueError("Enum with name: '%s' not found!" % enum_name) + + @classmethod + def findEnumerators(cls, enum_name, source_file): + enum_text = SourceEnumerator.findEnum(enum_name, source_file) + + enumerator_pattern = re.compile(r"(\w+?)\s*?=\s*?(\d+)") + + enumerators = [] + for enumerator in enumerator_pattern.findall(enum_text): + enumerators.append((enumerator[0], int(enumerator[1]))) + + return enumerators diff --git a/tests/util/test_area.py b/tests/util/test_area.py new file mode 100644 index 0000000000..29c75c0c20 --- /dev/null +++ b/tests/util/test_area.py @@ -0,0 +1,125 @@ +import os.path + +from cwrap import BaseCClass +from resdata import ResdataPrototype + + +class TestArea(BaseCClass): + __test__ = False + + _test_area_alloc = ResdataPrototype( + "void* test_work_area_alloc__( char*, bool )", bind=False + ) + _free = ResdataPrototype("void test_work_area_free( test_area )") + _install_file = ResdataPrototype( + "void test_work_area_install_file( test_area , char* )" + ) + _copy_directory = ResdataPrototype( + "void test_work_area_copy_directory( test_area , char* )" + ) + _copy_file = ResdataPrototype("void test_work_area_copy_file( test_area , char* )") + _copy_directory_content = ResdataPrototype( + "void test_work_area_copy_directory_content( test_area , char* )" + ) + _copy_parent_directory = ResdataPrototype( + "void test_work_area_copy_parent_directory( test_area , char* )" + ) + _copy_parent_content = ResdataPrototype( + "void test_work_area_copy_parent_content( test_area , char* )" + ) + _get_cwd = ResdataPrototype("char* test_work_area_get_cwd( test_area )") + _get_original_cwd = ResdataPrototype( + "char* test_work_area_get_original_cwd( test_area )" + ) + + def __init__(self, test_name, store_area=False, c_ptr=None): + if c_ptr is None: + c_ptr = self._test_area_alloc(test_name, store_area) + + super(TestArea, self).__init__(c_ptr) + + def get_original_cwd(self): + return self._get_original_cwd() + + def get_cwd(self): + return self._get_cwd() + + def orgPath(self, path): + if os.path.isabs(path): + return path + else: + return os.path.abspath(os.path.join(self.get_original_cwd(), path)) + + # All the methods install_file() , copy_directory(), + # copy_parent_directory(), copy_parent_content(), + # copy_directory_content() and copy_file() expect an input + # argument which is relative to the original CWD - or absolute. + + def install_file(self, filename): + if os.path.isfile(self.orgPath(filename)): + self._install_file(filename) + else: + raise IOError("No such file:%s" % filename) + + def copy_directory(self, directory): + if os.path.isdir(self.orgPath(directory)): + self._copy_directory(directory) + else: + raise IOError("No such directory: %s" % directory) + + def copy_parent_directory(self, path): + if os.path.exists(self.orgPath(path)): + self._copy_parent_directory(path) + else: + raise IOError("No such file or directory: %s" % path) + + def copy_parent_content(self, path): + if os.path.exists(self.orgPath(path)): + self._copy_parent_content(path) + else: + raise IOError("No such file or directory: %s" % path) + + def copy_directory_content(self, directory): + if os.path.isdir(self.orgPath(directory)): + self._copy_directory_content(directory) + else: + raise IOError("No such directory: %s" % directory) + + def copy_file(self, filename): + if os.path.isfile(self.orgPath(filename)): + self._copy_file(filename) + else: + raise IOError("No such file:%s" % filename) + + def free(self): + self._free() + + def getFullPath(self, path): + if not os.path.exists(path): + raise IOError("Path not found:%s" % path) + + if os.path.isabs(path): + raise IOError("Path:%s is already absolute" % path) + + return os.path.join(self.get_cwd(), path) + + +class TestAreaContext(object): + __test__ = False + + def __init__(self, test_name, store_area=False): + self.test_name = test_name + self.store_area = store_area + + def __enter__(self): + """ + @rtype: TestArea + """ + self.test_area = TestArea(self.test_name, store_area=self.store_area) + return self.test_area + + def __exit__(self, exc_type, exc_val, exc_tb): + self.test_area.free() # free the TestData object (and cd back to the original dir) + self.test_area.free = None # avoid double free + del self.test_area + return False diff --git a/tests/util_tests/test_path_context.py b/tests/util_tests/test_path_context.py deleted file mode 100644 index acd181ddce..0000000000 --- a/tests/util_tests/test_path_context.py +++ /dev/null @@ -1,36 +0,0 @@ -import os -from resdata.util.test import PathContext, TestAreaContext -from tests import ResdataTest - - -class PathContextTest(ResdataTest): - def test_error(self): - with TestAreaContext("pathcontext"): - # Test failure on creating PathContext with an existing path - os.makedirs("path/1") - with self.assertRaises(OSError): - with PathContext("path/1"): - pass - - # Test failure on creating PathContext with an existing file - with open("path/1/file", "w") as f: - f.write("xx") - with self.assertRaises(OSError): - with PathContext("path/1/file"): - pass - - def test_chdir(self): - with PathContext("/tmp/pc"): - self.assertEqual(os.path.realpath(os.getcwd()), os.path.realpath("/tmp/pc")) - - def test_cleanup(self): - with TestAreaContext("pathcontext"): - os.makedirs("path/1") - - with PathContext("path/1/next/2/level"): - with open("../../file", "w") as f: - f.write("Crap") - - self.assertTrue(os.path.isdir("path/1")) - self.assertTrue(os.path.isdir("path/1/next")) - self.assertFalse(os.path.isdir("path/1/next/2")) diff --git a/tests/util_tests/test_rng.py b/tests/util_tests/test_rng.py index ec3c3a1c82..c05ad47f35 100644 --- a/tests/util_tests/test_rng.py +++ b/tests/util_tests/test_rng.py @@ -1,7 +1,8 @@ from resdata.util.enums import RngAlgTypeEnum, RngInitModeEnum from resdata.util.util import RandomNumberGenerator -from resdata.util.test import TestAreaContext + from tests import ResdataTest +from tests.util import TestAreaContext class RngTest(ResdataTest): diff --git a/tests/util_tests/test_work_area.py b/tests/util_tests/test_work_area.py index a03e8da7c3..02c97026e0 100644 --- a/tests/util_tests/test_work_area.py +++ b/tests/util_tests/test_work_area.py @@ -7,8 +7,8 @@ except ImportError: from unittest import skipIf -from resdata.util.test import TestAreaContext from tests import ResdataTest +from tests.util import TestAreaContext class WorkAreaTest(ResdataTest):