From 58c4169b72354c769d17029b17df2af04ba3a83c Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Mon, 20 Apr 2026 07:23:59 +0200 Subject: [PATCH 1/4] Add 'will be removed in version 7' to deprecation messages Also changes the deprecation message from plain warning to type warning. Note that some deprecation messages were not updated as there is no plan to remove in version 7. Also, monkey_the_camel methods now display deprecation warnings. --- pyproject.toml | 1 - python/resdata/geometry/surface.py | 1 + python/resdata/grid/rd_grid.py | 11 ++-- python/resdata/resfile/rd_file.py | 6 +- python/resdata/resfile/rd_kw.py | 14 ++-- python/resdata/rft/rd_rft.py | 12 ++-- python/resdata/summary/rd_sum.py | 84 +++++++++++++----------- python/resdata/summary/rd_sum_vector.py | 14 ++-- python/resdata/util/util/__init__.py | 6 +- python/resdata/util/util/lookup_table.py | 1 - setup.py | 1 + 11 files changed, 82 insertions(+), 69 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 35995347fc..64d7689dcd 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", diff --git a/python/resdata/geometry/surface.py b/python/resdata/geometry/surface.py index 92150fb50a..273ec248d0 100644 --- a/python/resdata/geometry/surface.py +++ b/python/resdata/geometry/surface.py @@ -3,6 +3,7 @@ """ Create a polygon """ + import os.path import ctypes 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/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_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..9671fe265a 100644 --- a/python/resdata/summary/rd_sum_vector.py +++ b/python/resdata/summary/rd_sum_vector.py @@ -1,5 +1,8 @@ from __future__ import print_function import warnings +from typing_extensions import deprecated + + from .rd_sum_node import SummaryNode @@ -27,7 +30,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 +91,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 +102,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/util/__init__.py b/python/resdata/util/util/__init__.py index 5ee33d9b9e..80bc61e627 100644 --- a/python/resdata/util/util/__init__.py +++ b/python/resdata/util/util/__init__.py @@ -56,10 +56,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 +97,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/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"], From 2eb1f804936d53cffbaac109d19e2d7f017dbe1a Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Mon, 20 Apr 2026 07:31:01 +0200 Subject: [PATCH 2/4] Remove 'from __future__' import only relevant for python 2. --- python/resdata/geometry/surface.py | 2 -- python/resdata/grid/faults/fault_block_layer.py | 1 - python/resdata/grid/faults/fault_segments.py | 2 -- python/resdata/rd_util.py | 2 -- python/resdata/resfile/rd_file_view.py | 1 - python/resdata/summary/rd_sum_vector.py | 1 - python/resdata/util/util/__init__.py | 2 -- python/resdata/util/util/vector_template.py | 2 -- tests/rd_tests/test_rft_equinor.py | 1 - 9 files changed, 14 deletions(-) diff --git a/python/resdata/geometry/surface.py b/python/resdata/geometry/surface.py index 273ec248d0..0a14e59142 100644 --- a/python/resdata/geometry/surface.py +++ b/python/resdata/geometry/surface.py @@ -1,5 +1,3 @@ -from __future__ import division - """ Create a polygon """ 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/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_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/summary/rd_sum_vector.py b/python/resdata/summary/rd_sum_vector.py index 9671fe265a..e84906cd81 100644 --- a/python/resdata/summary/rd_sum_vector.py +++ b/python/resdata/summary/rd_sum_vector.py @@ -1,4 +1,3 @@ -from __future__ import print_function import warnings from typing_extensions import deprecated diff --git a/python/resdata/util/util/__init__.py b/python/resdata/util/util/__init__.py index 80bc61e627..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 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/tests/rd_tests/test_rft_equinor.py b/tests/rd_tests/test_rft_equinor.py index ef76a3738c..af3f7e8652 100644 --- a/tests/rd_tests/test_rft_equinor.py +++ b/tests/rd_tests/test_rft_equinor.py @@ -1,5 +1,4 @@ #!/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 From 46a4523b1d81989dd12f676443538655a5bdfce0 Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Mon, 20 Apr 2026 07:31:16 +0200 Subject: [PATCH 3/4] Remove redundant hashbang --- tests/rd_tests/test_rft_equinor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/rd_tests/test_rft_equinor.py b/tests/rd_tests/test_rft_equinor.py index af3f7e8652..e1c39ebe94 100644 --- a/tests/rd_tests/test_rft_equinor.py +++ b/tests/rd_tests/test_rft_equinor.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import datetime from resdata.rft import ResdataRFTFile, ResdataRFTCell, ResdataPLTCell, WellTrajectory from tests import ResdataTest, equinor_test From 89639d71e3f7dceca56645a8081f4aea6f52eaad Mon Sep 17 00:00:00 2001 From: Eivind Jahren Date: Mon, 20 Apr 2026 07:35:44 +0200 Subject: [PATCH 4/4] Deprecate resdata.util.test Because pytest does not like deprecation warnings at collect time, it was necessary to copy the classes into tests straight away. --- pyproject.toml | 1 - python/resdata/util/test/debug_msg.py | 2 + python/resdata/util/test/extended_testcase.py | 13 +- python/resdata/util/test/import_test_case.py | 2 + python/resdata/util/test/lint_test_case.py | 2 + python/resdata/util/test/mock/rd_sum_mock.py | 3 + python/resdata/util/test/path_context.py | 2 + .../resdata/util/test/resdata_test_runner.py | 2 + python/resdata/util/test/source_enumerator.py | 2 + python/resdata/util/test/test_area.py | 2 + python/resdata/util/test/test_run.py | 4 + tests/__init__.py | 3 +- tests/bin_tests/test_summary_resample.py | 4 +- tests/conftest.py | 2 + tests/geometry_tests/test_cpolyline.py | 2 +- .../test_cpolyline_collection.py | 4 +- tests/geometry_tests/test_geo_pointset.py | 2 +- tests/geometry_tests/test_geo_region.py | 2 +- tests/geometry_tests/test_geometry_tools.py | 2 +- tests/geometry_tests/test_polyline.py | 2 +- tests/geometry_tests/test_surface.py | 2 +- tests/rd_tests/test_debug.py | 9 - tests/rd_tests/test_deprecation.py | 5 +- tests/rd_tests/test_fault_blocks.py | 2 +- tests/rd_tests/test_faults.py | 2 +- tests/rd_tests/test_fk_user_data.py | 2 +- tests/rd_tests/test_fortio.py | 2 +- tests/rd_tests/test_geertsma.py | 2 +- tests/rd_tests/test_grav.py | 3 +- tests/rd_tests/test_grid.py | 3 +- tests/rd_tests/test_grid_equinor.py | 3 +- tests/rd_tests/test_grid_equinor_coarse.py | 3 +- tests/rd_tests/test_grid_equinor_dual.py | 2 +- tests/rd_tests/test_grid_generator.py | 3 +- tests/rd_tests/test_layer.py | 2 +- tests/rd_tests/test_npv.py | 4 +- tests/rd_tests/test_rd_3dkw.py | 3 +- tests/rd_tests/test_rd_cmp.py | 4 +- tests/rd_tests/test_rd_file.py | 4 +- tests/rd_tests/test_rd_file_equinor.py | 4 +- tests/rd_tests/test_rd_kw.py | 2 +- tests/rd_tests/test_rd_kw_equinor.py | 2 +- tests/rd_tests/test_rd_sum.py | 2 +- tests/rd_tests/test_rd_type.py | 6 +- tests/rd_tests/test_sum.py | 5 +- tests/rd_tests/test_sum_equinor.py | 2 +- tests/util/__init__.py | 2 + tests/util/extended_testcase.py | 202 ++++++++++++++++++ tests/util/mock/__init__.py | 1 + tests/util/mock/rd_sum_mock.py | 66 ++++++ tests/util/source_enumerator.py | 41 ++++ tests/util/test_area.py | 125 +++++++++++ tests/util_tests/test_path_context.py | 36 ---- tests/util_tests/test_rng.py | 3 +- tests/util_tests/test_work_area.py | 2 +- 55 files changed, 524 insertions(+), 95 deletions(-) delete mode 100644 tests/rd_tests/test_debug.py create mode 100644 tests/util/__init__.py create mode 100644 tests/util/extended_testcase.py create mode 100644 tests/util/mock/__init__.py create mode 100644 tests/util/mock/rd_sum_mock.py create mode 100644 tests/util/source_enumerator.py create mode 100644 tests/util/test_area.py delete mode 100644 tests/util_tests/test_path_context.py diff --git a/pyproject.toml b/pyproject.toml index 64d7689dcd..2bb82a115b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,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/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/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_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):