diff --git a/CHANGELOG.md b/CHANGELOG.md index fc229bd..6840189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,5 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 They were `eumIGeographicalCoordinate` in metres whatever the projection. Files with a projected coordinate system are unchanged ([#47](https://github.com/DHI/mikecore-python/issues/47)). +- Reading an item's value type raises the DFS error when the native library + reports one, instead of returning `DataValueType.Instantaneous`. [Unreleased]: https://github.com/DHI/mikecore-python/compare/v0.3.a1...HEAD diff --git a/buildUtil/eumXMLProcess.py b/buildUtil/eumXMLProcess.py index 3083feb..94c9582 100644 --- a/buildUtil/eumXMLProcess.py +++ b/buildUtil/eumXMLProcess.py @@ -16,8 +16,8 @@ eumLines = eumFile.readlines() eumFile.close() -recItem = re.compile('"(eumI\w+)" MzId="(\w*)"') -recUnit = re.compile('"(eumU\w+)" MzId="(\w*)"') +recItem = re.compile(r'"(eumI\w+)" MzId="(\w*)"') +recUnit = re.compile(r'"(eumU\w+)" MzId="(\w*)"') itemDict = {} unitDict = {} @@ -38,12 +38,12 @@ print("# Predefined enums of EUM item types.") print("#") print("# Must be updated with every new release, or if the EUM.xml is updated") -print("# Run buildUtil\eumXMLProcess.py to create the lists") +print(r"# Run buildUtil\eumXMLProcess.py to create the lists") print("class eumItem(IntEnum):") for key in itemKeys: print(f" {itemDict[key]} = {key}") -print("") +print() print("# Predefined enums of EUM units.") print("#") print("# Must be updated with every new release, or if the EUM.xml is updated") diff --git a/mikecore/DfsBuilder.py b/mikecore/DfsBuilder.py index 9b48cbd..afee788 100644 --- a/mikecore/DfsBuilder.py +++ b/mikecore/DfsBuilder.py @@ -329,11 +329,11 @@ def CreateFile(self, filename): fnp.value, headerPointer, ctypes.byref(filePointer) ) - except Exception as e: + except Exception: # In case of any exception, destroy the header. if headerPointer.value is not None: DfsDLL.Wrapper.dfsHeaderDestroy(ctypes.byref(headerPointer)) - raise e + raise # The create function will free ressources, if something fails. dfsFile = DfsFile() @@ -468,12 +468,12 @@ def AddStaticItem(self, staticItem): DfsBuilder.__SetValuesToItem(dfsFile.headPointer, itemPointer, staticItem) # From now on the responsibility of the staticVectorPointer is taken over bye the DfsStaticItem (ending the try-catch) - except Exception as e: + except Exception: # As long as the static vector pointer is not null, the # responsibility for destroying the header structure is here. if staticVectorPointer.value is not None: DfsDLL.Wrapper.dfsStaticDestroy(ctypes.byref(staticVectorPointer)) - raise e + raise # Create a DfsStaticItem that belongs to the current dfs file myStaticItem = DfsStaticItem(dfsFile, staticVectorPointer, itemPointer) diff --git a/mikecore/DfsFile.py b/mikecore/DfsFile.py index d6fbd5f..fc80ea9 100644 --- a/mikecore/DfsFile.py +++ b/mikecore/DfsFile.py @@ -1167,16 +1167,15 @@ def WriteItemTimeStep(self, itemNumber, timestepIndex, time, data): # More elaborate action is required, when appending to file. If appending then # (itemNumber == _fpItemNumber && timestepIndex == _fileInfo.TimeAxis.NumberOfTimeSteps == _fpTimeStepIndex) - if timestepIndex == self.FileInfo.TimeAxis.NumberOfTimeSteps: - if ( - timestepIndex == self.fpTimeStepIndex - and itemNumber != self.fpItemNumber - or timestepIndex != self.fpTimeStepIndex - and itemNumber != 1 - ): - raise IndexError( - "Wrong item number while trying to append item data to file. Item data must be appended in order, and for all items in the time step" - ) + if timestepIndex == self.FileInfo.TimeAxis.NumberOfTimeSteps and ( + timestepIndex == self.fpTimeStepIndex + and itemNumber != self.fpItemNumber + or timestepIndex != self.fpTimeStepIndex + and itemNumber != 1 + ): + raise IndexError( + "Wrong item number while trying to append item data to file. Item data must be appended in order, and for all items in the time step" + ) # Position file pointer self.__FpFindItemTimeStep(itemNumber, timestepIndex) @@ -1249,11 +1248,13 @@ def WriteItemTimeStepNext(self, time, data): self.headPointer, self.filePointer, ctypes.c_double(time), data.ctypes.data ) - if self.__FpDynamicIncrement(): - if self.fpTimeStepIndex > self.FileInfo.TimeAxis.NumberOfTimeSteps: - # One entire time step (all items) has just been written to file, - # increment the number of time steps - self.FileInfo.TimeAxis.IncrementNumberOfTimeSteps(time) + if ( + self.__FpDynamicIncrement() + and self.fpTimeStepIndex > self.FileInfo.TimeAxis.NumberOfTimeSteps + ): + # One entire time step (all items) has just been written to file, + # increment the number of time steps + self.FileInfo.TimeAxis.IncrementNumberOfTimeSteps(time) def Reset(self): """ @@ -1365,12 +1366,12 @@ def ReadDfs0DataDouble(self, itemsToLoad=None): # Need to handle StartTimeOffset similar to in __GetTime timeaxis = self.FileInfo.TimeAxis - if timeaxis.TimeAxisType == TimeAxisType.TimeEquidistant: - if timeaxis.StartTimeOffset != 0.0: - data[:, 0] = data[:, 0] + timeaxis.StartTimeOffset - elif timeaxis.TimeAxisType == TimeAxisType.CalendarEquidistant: - if timeaxis.StartTimeOffset != 0.0: - data[:, 0] = data[:, 0] + timeaxis.StartTimeOffset + if ( + timeaxis.TimeAxisType + in (TimeAxisType.TimeEquidistant, TimeAxisType.CalendarEquidistant) + and timeaxis.StartTimeOffset != 0.0 + ): + data[:, 0] = data[:, 0] + timeaxis.StartTimeOffset return data @@ -2112,7 +2113,8 @@ def ToDfsDateStrings(datetime): @staticmethod def dfsGetItemValueType(itemPointer): valueTypeInt = ctypes.c_int() - err = DfsDLL.Wrapper.dfsGetItemValueType( + rok = DfsDLL.Wrapper.dfsGetItemValueType( itemPointer, ctypes.byref(valueTypeInt) ) + DfsDLL.CheckReturnCode(rok) return DataValueType(valueTypeInt.value) diff --git a/mikecore/DfsuBuilder.py b/mikecore/DfsuBuilder.py index 12de450..e2a8820 100644 --- a/mikecore/DfsuBuilder.py +++ b/mikecore/DfsuBuilder.py @@ -730,19 +730,13 @@ def CreateDfsu(self, dfsBuilder, elementType, nodesPerElmt, connectivityArray): ) # Element type - elmtTypeItem = dfsBuilder.AddCreateStaticItem( - "Element type", intCode, elementType - ) + dfsBuilder.AddCreateStaticItem("Element type", intCode, elementType) # No of nodes (per element) - nodesPerElmtItem = dfsBuilder.AddCreateStaticItem( - "No of nodes", intCode, nodesPerElmt - ) + dfsBuilder.AddCreateStaticItem("No of nodes", intCode, nodesPerElmt) # Connectivity - connectivityItem = dfsBuilder.AddCreateStaticItem( - "Connectivity", intCode, connectivityArray - ) + dfsBuilder.AddCreateStaticItem("Connectivity", intCode, connectivityArray) # Spectral frequencyItem = ( diff --git a/mikecore/DfsuFile.py b/mikecore/DfsuFile.py index 1918cef..9e8883d 100644 --- a/mikecore/DfsuFile.py +++ b/mikecore/DfsuFile.py @@ -272,11 +272,10 @@ def __Init(self, dfsFile, build=False): self.NumberOfElements = self.ElementIds.size # self.NumberOfNodes = self.X.size - if not build: - # In append mode, move the file pointer to end of file - # It was moved elsewhere when reading static data... - if self.dfsFile.FileMode == DfsFileMode.Append: - self.dfsFile.FindTimeStep(self.NumberOfTimeSteps) + # In append mode, move the file pointer to end of file + # It was moved elsewhere when reading static data... + if not build and self.dfsFile.FileMode == DfsFileMode.Append: + self.dfsFile.FindTimeStep(self.NumberOfTimeSteps) def Dispose(self): """ @@ -655,8 +654,7 @@ def FindTopLayerElementsXY(elementTable, x, y): dx = x2 - x1 dy = y2 - y1 nodeDist2 = dx * dx + dy * dy - if nodeDist2 > maxNodeDist2: - maxNodeDist2 = nodeDist2 + maxNodeDist2 = max(maxNodeDist2, nodeDist2) # Check if element center coordinates differ more than a tolerance # times the reference lenght - the maximum node distance. @@ -681,8 +679,7 @@ def FindMaxNumberOfLayers(topLayerElements): maxLayers = topLayerElements[0] + 1 for i in range(1, topLayerElements.size): layers = topLayerElements[i] - topLayerElements[i - 1] - if layers > maxLayers: - maxLayers = layers + maxLayers = max(maxLayers, layers) return maxLayers @staticmethod @@ -697,6 +694,5 @@ def FindMinNumberOfLayers(topLayerElements): minLayers = topLayerElements[0] + 1 for i in range(1, topLayerElements.size): layers = topLayerElements[i] - topLayerElements[i - 1] - if layers < minLayers: - minLayers = layers + minLayers = min(minLayers, layers) return minLayers diff --git a/mikecore/Projections.py b/mikecore/Projections.py index 6b5d859..37df105 100644 --- a/mikecore/Projections.py +++ b/mikecore/Projections.py @@ -1109,9 +1109,8 @@ def Create(projectionString: str, validateProjectionString: bool = True): raise Exception( "Projection string cannot be null or empty", "projectionString" ) - if validateProjectionString: - if not MapProjection.IsValid(projectionString): - raise Exception("Not a valid projection string", "projectionString") + if validateProjectionString and not MapProjection.IsValid(projectionString): + raise Exception("Not a valid projection string", "projectionString") return MapProjection(projectionString, mustFree=True) # / @@ -1137,9 +1136,8 @@ def CreatePointer( # / def __del__(self): # Release ressources on the unmanaged side when garbage collected - if self._mustFree: - if self._mzMapProjPointer.value is not None: - MzCartDLL.MzMapProjDestroy(self._mzMapProjPointer) + if self._mustFree and self._mzMapProjPointer.value is not None: + MzCartDLL.MzMapProjDestroy(self._mzMapProjPointer) _mzMapProjPointer = ctypes.c_void_p() ##/ @@ -1523,9 +1521,8 @@ def __init__( self._mzCartPointer = ctypes.c_void_p(0) - if validateProjectionString: - if not MapProjection.IsValid(projectionString): - raise Exception("Not a valid projection string", "projectionString") + if validateProjectionString and not MapProjection.IsValid(projectionString): + raise Exception("Not a valid projection string", "projectionString") if lonOrigin is None: lonOrigin, latOrigin = MapProjection.ProjectionOrigin( @@ -1697,9 +1694,8 @@ def CreateGeoOrigin( ): if projectionString is None or projectionString == "": raise ValueError("Projection string can not be null or empty") - if validateProjectionString: - if not MapProjection.IsValid(projectionString): - raise ValueError("Not a valid projection string") + if validateProjectionString and not MapProjection.IsValid(projectionString): + raise ValueError("Not a valid projection string") cart = Cartography( projectionString, lonOrigin, @@ -1733,9 +1729,8 @@ def CreateProjOrigin( ): if projectionString is None or projectionString == "": raise ValueError("Projection string cannot be null or empty") - if validateProjectionString: - if not MapProjection.IsValid(projectionString): - raise ValueError("Not a valid projection string") + if validateProjectionString and not MapProjection.IsValid(projectionString): + raise ValueError("Not a valid projection string") proj = MapProjection.Create(projectionString, validateProjectionString) lonOrigin, latOrigin = proj.Proj2Geo(east, north) orientationGeo = proj.Proj2GeoRotation(east, north, orientationProj) diff --git a/mikecore/eum.py b/mikecore/eum.py index 8fcddce..a287061 100644 --- a/mikecore/eum.py +++ b/mikecore/eum.py @@ -1452,7 +1452,7 @@ def Init(libfilepath=None, libfilename=None): # TODO: Should this not be simpler? eumFilePath = path + "/EUM.xml" eumFilePathP = ctypes.c_char_p(eumFilePath.encode("ascii")) - res = lib.eumSetupLoadLinux(eumFilePathP) + lib.eumSetupLoadLinux(eumFilePathP) lib.eumUnitGetParameters.argtypes = [ ctypes.c_int32, @@ -1536,7 +1536,7 @@ def DecodeString( # / A hashtable with item type text description, numeric key pairs. @staticmethod def CreateItemHashtable() -> dict: - itemHash = dict() + itemHash = {} n = eumWrapper.eumGetItemTypeCount() for i in range(1, n + 1): ok, key, desc = eumWrapper.eumGetItemTypeSeq(i) @@ -1554,7 +1554,7 @@ def CreateItemHashtable() -> dict: # / @staticmethod def CreateUnitHashTable(abbreviations: bool = False): - unitHash = dict() # current number of unique desc/abbrs. + unitHash = {} # current number of unique desc/abbrs. prevKey = eumUnit.eumUUnitUndefined ok, unitKey, desc = eumWrapper.eumGetNextUnit(prevKey) while ok: diff --git a/miketools/Dfs0ToAscii.py b/miketools/Dfs0ToAscii.py index bb00dfa..53025d7 100644 --- a/miketools/Dfs0ToAscii.py +++ b/miketools/Dfs0ToAscii.py @@ -14,25 +14,24 @@ def Dfs0ToAscii(dfs0FileName, txtFileName): txt.write("\n") txt.write(" Time") - for item in dfs.ItemInfo: - txt.write(f" {item.Name}") + txt.writelines(f" {item.Name}" for item in dfs.ItemInfo) txt.write("\n") txt.write(" Item") - for item in dfs.ItemInfo: - txt.write( - f" {item.Quantity.Item.value:11} {item.Quantity.Unit.value:11} {item.ValueType.name:11}" - ) + txt.writelines( + f" {item.Quantity.Item.value:11} {item.Quantity.Unit.value:11} {item.ValueType.name:11}" + for item in dfs.ItemInfo + ) txt.write("\n") txt.write(" Item") - for item in dfs.ItemInfo: - txt.write( - " {:11} {:11} {:11}".format( - '"' + item.Quantity.ItemDescription + '"', - '"' + item.Quantity.UnitDescription + '"', - item.ValueType.name, - ) + txt.writelines( + " {:11} {:11} {:11}".format( + '"' + item.Quantity.ItemDescription + '"', + '"' + item.Quantity.UnitDescription + '"', + item.ValueType.name, ) + for item in dfs.ItemInfo + ) txt.write("\n") # Only set for calendar time axes; otherwise times are written as offsets. diff --git a/miketools/DfsShowInfo.py b/miketools/DfsShowInfo.py index 6845924..25b189f 100644 --- a/miketools/DfsShowInfo.py +++ b/miketools/DfsShowInfo.py @@ -22,7 +22,6 @@ def DfsShowInfo(dfsFileName, showAxis=False): dfs.FileInfo.TimeAxis.TimeAxisType == TimeAxisType.CalendarEquidistant or dfs.FileInfo.TimeAxis.TimeAxisType == TimeAxisType.CalendarNonEquidistant ): - isCalendarTime = True startDateTime = dfs.FileInfo.TimeAxis.StartDateTime txt.write( f"Time : {dfs.FileInfo.TimeAxis.TimeAxisType}, {dfs.FileInfo.TimeAxis.NumberOfTimeSteps}, {startDateTime}\n" @@ -47,11 +46,10 @@ def DfsShowInfo(dfsFileName, showAxis=False): txt.write( f"item {item.ItemNumber!s:>2}: {item.Name!s:<40}: {item.ElementCount!s:>5}: {item.DataType.name!s:>6} {item.SpatialAxis.AxisType.name!s:>6} ({item.Quantity.ItemDescription!s:>11}: {item.Quantity.UnitDescription!s:>11}) \n" ) - if showAxis: - if item.SpatialAxis.AxisType is SpaceAxisType.EqD1: - txt.write( - f" axis : dx = {item.SpatialAxis.Dx}, xCount = {item.SpatialAxis.XCount}, x0 = {item.SpatialAxis.X0} ({item.SpatialAxis.AxisUnit.name})\n" - ) + if showAxis and item.SpatialAxis.AxisType is SpaceAxisType.EqD1: + txt.write( + f" axis : dx = {item.SpatialAxis.Dx}, xCount = {item.SpatialAxis.XCount}, x0 = {item.SpatialAxis.X0} ({item.SpatialAxis.AxisUnit.name})\n" + ) dfs.Close() @@ -74,7 +72,6 @@ def DfsuShowInfo(dfsFileName, showMesh=False): dfs.FileInfo.TimeAxis.TimeAxisType == TimeAxisType.CalendarEquidistant or dfs.FileInfo.TimeAxis.TimeAxisType == TimeAxisType.CalendarNonEquidistant ): - isCalendarTime = True startDateTime = dfs.FileInfo.TimeAxis.StartDateTime txt.write( f"Time : {dfs.FileInfo.TimeAxis.TimeAxisType}, {dfs.FileInfo.TimeAxis.NumberOfTimeSteps}, {startDateTime}\n" diff --git a/pyproject.toml b/pyproject.toml index 4e1a816..a858f1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,7 +69,66 @@ line-ending = "lf" # ruff takes its target version from requires-python. [tool.ruff.lint] -select = ["E4", "E7", "E9", "F", "UP", "B"] +select = [ + "E4", "E7", "E9", "F", "UP", "B", + # The other stable rules ruff tags correctness, complexity or performance + # (the "category" field of `ruff rule --all --output-format json`). F, UP, B and + # E9 already hold theirs. Rules for frameworks mikecore does not use (FastAPI, + # pandas) are left out. TID255 joins once CI's ruff has it as stable. + + # flake8-comprehensions + "C400", "C401", "C402", "C403", "C404", "C405", "C406", "C408", "C409", "C410", + "C411", "C413", "C414", "C415", "C417", "C418", "C419", "C420", + # flake8-executable + "EXE002", "EXE004", + # flake8-future-annotations + "FA102", + # flynt + "FLY002", + # refurb + "FURB105", "FURB110", "FURB122", "FURB129", "FURB132", "FURB136", "FURB157", + "FURB161", "FURB162", "FURB163", "FURB166", "FURB168", "FURB169", "FURB171", + "FURB177", "FURB181", "FURB188", "FURB192", + # flake8-logging-format + "G101", "G201", + # flake8-logging + "LOG001", + # Perflint + "PERF101", "PERF102", "PERF402", + # flake8-pie + "PIE794", "PIE800", "PIE807", "PIE808", "PIE810", + # Pylint + "PLC0131", "PLC0206", "PLC0207", "PLC0208", "PLC0414", "PLC3002", "PLE0100", + "PLE0101", "PLE0115", "PLE0116", "PLE0117", "PLE0118", "PLE0241", "PLE0604", + "PLE0605", "PLE0643", "PLE1132", "PLE1142", "PLE1205", "PLE1206", "PLE1300", + "PLE1307", "PLE1310", "PLE1507", "PLE1700", "PLR0133", "PLR0206", "PLR0402", + "PLR1708", "PLR1711", "PLR1730", "PLR1733", "PLR1736", "PLW0128", "PLW0129", + "PLW0131", "PLW0133", "PLW0177", "PLW0245", "PLW0604", "PLW1501", "PLW1507", + "PLW2101", + # flake8-pytest-style + "PT008", "PT010", "PT014", "PT024", "PT025", "PT026", + # flake8-use-pathlib + "PTH210", + # flake8-pyi + "PYI010", "PYI012", "PYI013", "PYI016", "PYI019", "PYI030", "PYI035", "PYI041", + "PYI044", "PYI045", "PYI048", "PYI055", "PYI059", "PYI064", + # Ruff-specific rules + "RUF007", "RUF010", "RUF015", "RUF016", "RUF017", "RUF019", "RUF020", "RUF026", + "RUF030", "RUF034", "RUF037", "RUF046", "RUF049", "RUF051", "RUF053", "RUF057", + "RUF058", "RUF060", "RUF068", "RUF200", + # flake8-simplify + "SIM101", "SIM102", "SIM103", "SIM107", "SIM110", "SIM113", "SIM117", "SIM118", + "SIM201", "SIM202", "SIM208", "SIM210", "SIM211", "SIM220", "SIM221", "SIM222", + "SIM223", "SIM401", "SIM905", "SIM911", + # flake8-debugger + "T100", + # flake8-type-checking + "TC004", "TC007", "TC010", + # tryceratops + "TRY201", "TRY203", "TRY401", + # pycodestyle + "W605", +] # The C#-style API is re-exported through star imports throughout. ignore = [ "F403", "F405", @@ -79,7 +138,6 @@ ignore = [ "E731", # lambda assignment "E741", # ambiguous variable name "F811", # duplicated test helpers whose bodies differ - "F841", # unused variables # Defaults like DfsParameters() and np.float32(...) are never mutated. "B008", ] diff --git a/tests/Test.py b/tests/Test.py index 6ce46bf..7f85e5a 100644 --- a/tests/Test.py +++ b/tests/Test.py @@ -1,5 +1,5 @@ # To run all test in a Python environment: import sys -sys.path.insert(0, "C:\Work\python\mikecore") +sys.path.insert(0, r"C:\Work\python\mikecore") import tests.test_run_all diff --git a/tests/examples_dfs2.py b/tests/examples_dfs2.py index fd45ea2..a7229c7 100644 --- a/tests/examples_dfs2.py +++ b/tests/examples_dfs2.py @@ -16,16 +16,20 @@ def ReadingDfs2File(filename): axisEqD2 = dfs2File.SpatialAxis dx = axisEqD2.Dx # 900 dy = axisEqD2.Dy # 900 + assert (dx, dy) == (900, 900) # Header information is contained in the IDfsFileInfo fileInfo = dfs2File.FileInfo steps = fileInfo.TimeAxis.NumberOfTimeSteps # 13 projectionString = fileInfo.Projection.WKTString # "UTM-33" + assert projectionString == "UTM-33" # Information on each of the dynamic items, here the first one dynamicItemInfo = dfs2File.ItemInfo[0] nameOfFirstDynamicItem = dynamicItemInfo.Name # "H Water Depth m" typeOfFirstDynamicItem = dynamicItemInfo.DataType # Float + assert nameOfFirstDynamicItem == "H Water Depth m" + assert typeOfFirstDynamicItem == DfsSimpleType.Float # Read data of first item, third time step (items start by 1, timesteps by 0), # assuming data is of type float. diff --git a/tests/examples_dfsu.py b/tests/examples_dfsu.py index 312aace..17466e6 100644 --- a/tests/examples_dfsu.py +++ b/tests/examples_dfsu.py @@ -23,15 +23,22 @@ def ReadingDfsuFile(filename): numberOfNodes = file.NumberOfNodes # 2057 firstNodeXCoordinate = file.X[0] # 359978.8 firstElementNodes = file.ElementTable[0] # [1, 2, 3] + assert (numberOfElements, numberOfNodes) == (3636, 2057) + assert math.isclose(firstNodeXCoordinate, 359978.8, abs_tol=0.1) + assert list(firstElementNodes) == [1, 2, 3] # Read dynamic item info firstItemName = file.ItemInfo[0].Name # "Surface elevation" quantity = file.ItemInfo[0].Quantity # eumISurfaceElevation in eumUmeter + assert firstItemName == "Surface elevation" + assert quantity.Item == eumItem.eumISurfaceElevation + assert quantity.Unit == eumUnit.eumUmeter # load data for the first item, 6th timestep itemTimeStepData = file.ReadItemTimeStep(1, 5).Data # Read the value of the third element thirdElementValue = itemTimeStepData[2] # 0.0014070312 + assert math.isclose(thirdElementValue, 0.0014070312, rel_tol=1e-6) file.Close() @@ -158,7 +165,6 @@ def ExtractDfs0FromDfsu(dfsuFileNamePath, elmtsIndices): # Create a dfs0 file for each element in elmtsIndices dfs0Files = [] - timeSpan = source.TimeStepInSeconds * source.NumberOfTimeSteps for k in range(elmtsIndices.size): # Index of element to create dfs0 for elmtsIndex = elmtsIndices[k] @@ -216,7 +222,7 @@ def ExtractDfs0FromDfsu(dfsuFileNamePath, elmtsIndices): for i in range(source.NumberOfTimeSteps): for j in range(len(source.ItemInfo)): dfsuItemData = dfsuItemDatas[j] - ok = source.ReadItemTimeStep(dfsuItemData, i) + source.ReadItemTimeStep(dfsuItemData, i) floats = dfsuItemData.Data # write data to dfs0's @@ -413,7 +419,7 @@ def ExtractDfsu2DLayerFrom3D(filenameDfsu3, filenameDfsu2, layerNumber): for j in range(len(dfsu3File.ItemInfo)): # Read data from 3D dfsu data3Item = dfsu3ItemDatas[j] - ok = dfsu3File.ReadItemTimeStep(data3Item, i) + dfsu3File.ReadItemTimeStep(data3Item, i) # 3D data data3 = data3Item.Data diff --git a/tests/test_dfs_basic.py b/tests/test_dfs_basic.py index 497b012..fb70f39 100644 --- a/tests/test_dfs_basic.py +++ b/tests/test_dfs_basic.py @@ -1,7 +1,9 @@ +import ctypes + import pytest from mikecore.DfsDLL import DfsDLL -from mikecore.DfsFile import DfsFile, DfsFileMode, TimeAxisType +from mikecore.DfsFile import DfsDLLUtil, DfsFile, DfsFileMode, TimeAxisType from mikecore.DfsFileFactory import DfsFileFactory @@ -58,6 +60,11 @@ def test_error_reporting(): print("Exception:", e) +def test_item_value_type_reports_dfs_error(): + with pytest.raises(Exception, match="DFS error code 1000"): + DfsDLLUtil.dfsGetItemValueType(ctypes.c_void_p()) + + def test_open_with_integer_mode(): dfs = DfsFile() diff --git a/tests/test_dfs_static_item.py b/tests/test_dfs_static_item.py index 701e902..5217b67 100644 --- a/tests/test_dfs_static_item.py +++ b/tests/test_dfs_static_item.py @@ -32,13 +32,13 @@ def test_static_item(self): elif eumItem.eumIGeographicalCoordinate == staticItem.Quantity.Item: assert eumUnit.eumUmeter == staticItem.Quantity.Unit else: - assert "X coordinate axis item type mismatch" == "" + self.fail("X coordinate axis item type mismatch") if ( staticItem.DataType != DfsSimpleType.Double and staticItem.DataType != DfsSimpleType.Float ): - assert "DataType of X static item mismatch" == "" + self.fail("DataType of X static item mismatch") # assert deleteValueFloat == staticItem.ReferenceCoordinateX # assert deleteValueFloat == staticItem.ReferenceCoordinateY diff --git a/tests/test_dfsbuilder.py b/tests/test_dfsbuilder.py index 82263b8..681b77f 100644 --- a/tests/test_dfsbuilder.py +++ b/tests/test_dfsbuilder.py @@ -58,7 +58,7 @@ def test_validate_empty_builder(): def test_empty_title(landuse: DfsBuilder, tmp_path): # Create and get file landuse.CreateFile(str(tmp_path / "notused.dfs2")) - file = landuse.GetFile() + landuse.GetFile() def test_getfile_not_possible_if_not_created(landuse: DfsBuilder): @@ -75,7 +75,7 @@ def test_getfiletwice_not_allowed(landuse: DfsBuilder, tmp_path): # Create and get file builder.CreateFile(str(tmp_path / "notused.dfs2")) - file = builder.GetFile() + builder.GetFile() with pytest.raises(Exception, match="File has been returned"): builder.GetFile() @@ -86,7 +86,7 @@ def test_filetitle_after_create_not_possible(landuse: DfsBuilder, tmp_path): # Create and get file builder.CreateFile(str(tmp_path / "notused.dfs2")) - file = builder.GetFile() + builder.GetFile() with pytest.raises(Exception, match="File has been returned"): builder.SetFileTitle("too late") @@ -97,7 +97,7 @@ def test_apptitle_after_create_not_possible(landuse: DfsBuilder, tmp_path): # Create and get file builder.CreateFile(str(tmp_path / "notused.dfs2")) - file = builder.GetFile() + builder.GetFile() with pytest.raises(Exception, match="File has been returned"): builder.SetApplicationTitle("too late") diff --git a/tests/test_dfsu2D.py b/tests/test_dfsu2D.py index 3eac70e..5747cd9 100644 --- a/tests/test_dfsu2D.py +++ b/tests/test_dfsu2D.py @@ -447,13 +447,15 @@ def test_ExtractDfsu2DLayerFrom3DLayerOutOfRange(self): numberOfLayers = dfsu3.NumberOfLayers dfsu3.Close() for layerNumber in [0, numberOfLayers + 1, -(numberOfLayers + 1)]: - with self.subTest(layerNumber=layerNumber): - with self.assertRaisesRegex(Exception, "Layer number is out of range"): - ExamplesDfsu.ExtractDfsu2DLayerFrom3D( - "testdata/OdenseHD3D.dfsu", - "testdata/testtmp/test_OdenseHD3D_outofrange.dfsu", - layerNumber, - ) + with ( + self.subTest(layerNumber=layerNumber), + self.assertRaisesRegex(Exception, "Layer number is out of range"), + ): + ExamplesDfsu.ExtractDfsu2DLayerFrom3D( + "testdata/OdenseHD3D.dfsu", + "testdata/testtmp/test_OdenseHD3D_outofrange.dfsu", + layerNumber, + ) def test_ExtractDfsu2DLayerFrom2DFails(self): with self.assertRaisesRegex(Exception, "not a 3D dfsu file"):