From abbef8404e2ff1fd2fcde4ed6862004ce8ee3c8a Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:06:15 +0100 Subject: [PATCH 01/59] Linting: Fix f-string (UP032) --- pyhope/basis/basis_connect.py | 16 +++++++-------- pyhope/basis/basis_watertight.py | 22 ++++++++++----------- pyhope/common/common_template.py | 2 +- pyhope/gmsh/gmsh_install.py | 2 +- pyhope/io/io.py | 14 ++++++------- pyhope/mesh/connect/connect.py | 26 ++++++++++++------------- pyhope/mesh/extrude/mesh_extrude.py | 8 ++++---- pyhope/mesh/mesh.py | 4 ++-- pyhope/mesh/mesh_builtin.py | 8 ++++---- pyhope/mesh/mesh_external.py | 6 +++--- pyhope/mesh/mesh_sort.py | 4 ++-- pyhope/mesh/reader/reader_gmsh.py | 4 ++-- pyhope/mesh/reader/reader_hopr.py | 6 +++--- pyhope/mesh/topology/mesh_splittohex.py | 6 +++--- pyhope/mesh/topology/mesh_topology.py | 22 ++++++++++----------- pyhope/mesh/transform/mesh_transform.py | 2 +- pyhope/output/output.py | 4 ++-- pyhope/readintools/commandline.py | 2 +- pyhope/readintools/readintools.py | 20 +++++++++---------- pyhope/script/pyhope_cli.py | 3 +-- 20 files changed, 90 insertions(+), 91 deletions(-) diff --git a/pyhope/basis/basis_connect.py b/pyhope/basis/basis_connect.py index 2616c128..5d6957a5 100644 --- a/pyhope/basis/basis_connect.py +++ b/pyhope/basis/basis_connect.py @@ -220,16 +220,16 @@ def CheckConnect() -> None: # Print the information strLen = max(len(str(side.sideID+1)), len(str(nbside.sideID+1))) print(hopout.warn(f'> Element { elem.elemID+1:>{strLen}}, Side { side.face}, Side { side.sideID+1:>{strLen}}')) # noqa: E501 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[ 0, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[ 0, -1]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[-1, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[-1, -1]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[ 0, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[ 0, -1]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[-1, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[-1, -1]]) + ']')) # noqa: E271 # print() print(hopout.warn(f'> Element {nbelem.elemID+1:>{strLen}}, Side {nbside.face}, Side {nbside.sideID+1:>{strLen}}')) # noqa: E501 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[ 0, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[ 0, -1]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, -1]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[ 0, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[ 0, -1]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[-1, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[-1, -1]]) + ']')) # noqa: E271 hopout.warning(f'Connectivity check failed for {len(results)} / {nconn} connections!') sys.exit(1) diff --git a/pyhope/basis/basis_watertight.py b/pyhope/basis/basis_watertight.py index ab9a6367..5f99adde 100644 --- a/pyhope/basis/basis_watertight.py +++ b/pyhope/basis/basis_watertight.py @@ -348,24 +348,24 @@ def CheckWatertight() -> None: print() # Check if side is oriented inwards errStr = 'Side is oriented inwards!' if nSurfErr < 0 \ - else 'Surface normals are not within tolerance {:9.6e} > {:9.6e}'.format(nSurfErr, tol) + else f'Surface normals are not within tolerance {nSurfErr:9.6e} > {tol:9.6e}' print(hopout.warn(errStr, length=len(errStr)+16)) # Print the information strLen = max(len(str(side.sideID+1)), len(str(nbside.sideID+1))) print(hopout.warn(f'> Element { elem.elemID+1:>{strLen}}, Side { side.face}, Side { side.sideID+1:>{strLen}}')) # noqa: E501 - print(hopout.warn('> Normal vector: [' + ' '.join('{:12.3f}'.format(s) for s in nSurf) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[ 0, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[ 0, -1]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[-1, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[-1, -1]]) + ']')) # noqa: E271 + print(hopout.warn('> Normal vector: [' + ' '.join(f'{s:12.3f}' for s in nSurf) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[ 0, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[ 0, -1]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[-1, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[ nodes[-1, -1]]) + ']')) # noqa: E271 # print() print(hopout.warn(f'> Element {nbelem.elemID+1:>{strLen}}, Side {nbside.face}, Side {nbside.sideID+1:>{strLen}}')) # noqa: E501 - print(hopout.warn('> Normal vector: [' + ' '.join('{:12.3f}'.format(s) for s in nbnSurf) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[ 0, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[ 0, -1]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, 0]]) + ']')) # noqa: E271 - print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, -1]]) + ']')) # noqa: E271 + print(hopout.warn('> Normal vector: [' + ' '.join(f'{s:12.3f}' for s in nbnSurf) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[ 0, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[ 0, -1]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[-1, 0]]) + ']')) # noqa: E271 + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:12.3f}' for s in points[nbnodes[-1, -1]]) + ']')) # noqa: E271 hopout.error(f'Watertightness check failed for {len(results)} / {nconn} connections!') diff --git a/pyhope/common/common_template.py b/pyhope/common/common_template.py index d8982217..79140b28 100644 --- a/pyhope/common/common_template.py +++ b/pyhope/common/common_template.py @@ -74,7 +74,7 @@ def LoadTemplate(template: str, spec.loader.exec_module(templateModule) # Output filename of template - hopout.routine(' found: {}'.format(loc)) + hopout.routine(f' found: {loc}') # Stop once the module is successfully loaded break diff --git a/pyhope/gmsh/gmsh_install.py b/pyhope/gmsh/gmsh_install.py index 53242173..2944c672 100644 --- a/pyhope/gmsh/gmsh_install.py +++ b/pyhope/gmsh/gmsh_install.py @@ -162,7 +162,7 @@ def PkgsInstallGmsh(system: str, arch: str, version: str) -> None: if version == 'nrg': # Gitlab "python-gmsh" access lfs = 'yes' - lib = 'gmsh-{}-py3-none-{}_{}.whl'.format(Gitlab.LIB_VERSION[system][arch], system, arch) + lib = f'gmsh-{Gitlab.LIB_VERSION[system][arch]}-py3-none-{system}_{arch}.whl' # Create a temporary directory with tempfile.TemporaryDirectory() as path: diff --git a/pyhope/io/io.py b/pyhope/io/io.py index 7d9962b9..6d1ec903 100644 --- a/pyhope/io/io.py +++ b/pyhope/io/io.py @@ -110,7 +110,7 @@ def IO() -> None: nVertices: Final[int] = np.array(tuple(elem.type % 10 for elem in elems), dtype=np.int32).sum(dtype=int) # noqa: E272 nEdges: Final[int] = np.array(tuple(len(edges(elem.type)) for elem in elems), dtype=np.int32).sum(dtype=int) # noqa: E272 - fname = '{}_mesh.h5'.format(pname) + fname = f'{pname}_mesh.h5' elemInfo, elemIJK, sideInfo, nodeInfo, nodeCoords, \ FEMElemInfo, nFEMVertices, vertexInfo, vertexConnectInfo, nFEMEdges, edgeInfo, edgeConnectInfo, \ @@ -123,7 +123,7 @@ def IO() -> None: hopout.info(f'{ELEMTYPE(elemType)}: {count:12d}') hopout.sep() - hopout.routine('Writing HDF5 mesh to "{}"'.format(fname)) + hopout.routine(f'Writing HDF5 mesh to "{fname}"') with h5py.File(fname, mode='w') as f: # Store same basic information @@ -191,10 +191,10 @@ def IO() -> None: case MeshFormat.VTK.value: mesh = mesh_vars.mesh - fname = '{}_mesh.vtk'.format(pname) + fname = f'{pname}_mesh.vtk' hopout.sep() - hopout.routine('Writing VTK mesh to "{}"'.format(fname)) + hopout.routine(f'Writing VTK mesh to "{fname}"') mesh.write(fname, file_format='vtk42') @@ -206,7 +206,7 @@ def IO() -> None: MeshioGmshOrderingPatch() mesh = mesh_vars.mesh - fname = '{}_mesh.msh'.format(pname) + fname = f'{pname}_mesh.msh' # Instantiate the Gmsh cell type mapping gmshCellTypes = GMSHCELLTYPES() @@ -224,11 +224,11 @@ def IO() -> None: gmshMesh = meshio_to_gmsh(mesh) hopout.sep() - hopout.routine('Writing GMSH mesh to "{}"'.format(fname)) + hopout.routine(f'Writing GMSH mesh to "{fname}"') gmshMesh.write(fname, file_format='gmsh', binary=False) case _: # Default - hopout.error('Unknown output format {}, exiting...'.format(io_vars.outputformat)) + hopout.error(f'Unknown output format {io_vars.outputformat}, exiting...') def getMeshInfo() -> tuple[np.ndarray, # ElemInfo diff --git a/pyhope/mesh/connect/connect.py b/pyhope/mesh/connect/connect.py index 00ab38e2..f488c0fc 100644 --- a/pyhope/mesh/connect/connect.py +++ b/pyhope/mesh/connect/connect.py @@ -361,7 +361,7 @@ def ConnectMesh() -> None: corners = np.sort(mapFaces[iSide][:nCorners]) print(hopout.warn(f'> Side {cell_types}, Nodes {corners}')) for corner in corners: - print(hopout.warn('- Coordinates : [' + ' '.join('{:13.8f}'.format(s) for s in mesh.points[corner]) + ']')) + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in mesh.points[corner]) + ']')) # traceback.print_stack(file=sys.stdout) sys.exit(1) @@ -488,7 +488,7 @@ def ConnectMesh() -> None: print(hopout.warn(hopout.Colors.WARN + '─'*(46-16) + hopout.Colors.END)) for elemType in ELEM.TYPES: if elemType in passedTypes and passedTypes[elemType] > 0: - print(hopout.warn( ELEMTYPE(elemType) + ': {:12d}'.format(passedTypes[elemType]))) + print(hopout.warn( ELEMTYPE(elemType) + f': {passedTypes[elemType]:12d}')) nConnSide, nConnCenter = get_nonconnected_sides(sides, mesh) @@ -509,16 +509,16 @@ def ConnectMesh() -> None: nodes = np.transpose(np.array([elem.nodes[s] for s in face_to_nodes(side.face, elem.type, nGeo)])) if elem.type % 100 == 8: nodes = np.transpose(points[nodes] , axes=(2, 0, 1)) - print(hopout.warn('- Coordinates : [' + ' '.join('{:13.8f}'.format(s) for s in nodes[:, 0, 0]) + ']')) - print(hopout.warn('- Coordinates : [' + ' '.join('{:13.8f}'.format(s) for s in nodes[:, 0, -1]) + ']')) - print(hopout.warn('- Coordinates : [' + ' '.join('{:13.8f}'.format(s) for s in nodes[:, -1, 0]) + ']')) - print(hopout.warn('- Coordinates : [' + ' '.join('{:13.8f}'.format(s) for s in nodes[:, -1, -1]) + ']')) + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in nodes[:, 0, 0]) + ']')) + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in nodes[:, 0, -1]) + ']')) + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in nodes[:, -1, 0]) + ']')) + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in nodes[:, -1, -1]) + ']')) if side is not nConnSide[-1]: print() # Empty line for spacing else: nodes = points[nodes] for node in nodes: - print(hopout.warn('- Coordinates : [' + ' '.join('{:13.8f}'.format(s) for s in node) + ']')) + print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in node) + ']')) if side is not nConnSide[-1]: print() # Empty line for spacing hopout.error('Could not connect {} / {} side{}'.format(len(nConnSide), len(sides), '' if len(sides) == 1 else 's')) @@ -550,12 +550,12 @@ def ConnectMesh() -> None: nsides = len(sides) - nmortarsmallsides hopout.sep() - hopout.info(' Number of sides : {:12d}'.format(nsides)) - hopout.info(' Number of inner sides : {:12d}'.format(ninnersides)) - hopout.info(' Number of mortar sides (big) : {:12d}'.format(nmortarbigsides)) - hopout.info(' Number of mortar sides (small) : {:12d}'.format(nmortarsmallsides)) - hopout.info(' Number of boundary sides : {:12d}'.format(nbcsides)) - hopout.info(' Number of periodic sides : {:12d}'.format(nperiodicsides)) + hopout.info(f' Number of sides : {nsides:12d}') + hopout.info(f' Number of inner sides : {ninnersides:12d}') + hopout.info(f' Number of mortar sides (big) : {nmortarbigsides:12d}') + hopout.info(f' Number of mortar sides (small) : {nmortarsmallsides:12d}') + hopout.info(f' Number of boundary sides : {nbcsides:12d}') + hopout.info(f' Number of periodic sides : {nperiodicsides:12d}') mesh_vars.sides = sides mesh_vars.elems = elems diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index aa632ebc..ba05fe29 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -83,7 +83,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: hopout.error('Mesh contains no suitable surface cells for extrusion, exiting...') if nGeo > 2: - hopout.error('nGeo = {} not supported for mesh extrusion'.format(nGeo)) + hopout.error(f'nGeo = {nGeo} not supported for mesh extrusion') hopout.info('Extruding surface to volume mesh') @@ -94,7 +94,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: # Continue with extrusion hopout.sep() - hopout.routine(' Template: {}'.format(extrTemplate)) + hopout.routine(f' Template: {extrTemplate}') # Setup the extrusion extrShifts = LoadTemplate(extrTemplate.strip().lower(), __file__, 'Extrusion').ExtrudeTemplate() @@ -188,9 +188,9 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: # Consistency checks if faceMap is None: - raise ValueError('Missing faceMap for element type {}'.format(mtype)) + raise ValueError(f'Missing faceMap for element type {mtype}') if extrude is None or faces is None: - hopout.error('Element type {} not supported for extruding'.format(mtype), traceback=True) + hopout.error(f'Element type {mtype} not supported for extruding', traceback=True) # Obtain the element type elemType = elemTypeClass.inam[elemNum] diff --git a/pyhope/mesh/mesh.py b/pyhope/mesh/mesh.py index ff6421eb..fa46cb66 100644 --- a/pyhope/mesh/mesh.py +++ b/pyhope/mesh/mesh.py @@ -201,7 +201,7 @@ def GenerateMesh() -> None: case MeshMode.External.value: # External mesh mesh = MeshExternal() case _: # Default - hopout.error('Unknown mesh mode {}, exiting...'.format(mesh_vars.mode), traceback=True) + hopout.error(f'Unknown mesh mode {mesh_vars.mode}, exiting...', traceback=True) # Extrude mesh if requested mesh = MeshExtrude(mesh) @@ -217,7 +217,7 @@ def GenerateMesh() -> None: if any(s in cellType.type for s in mesh_vars.ELEMTYPE.type.keys()): nElems += mesh.get_cells_type(cellType.type).shape[0] - hopout.routine('Generated mesh with {} cells'.format(nElems)) + hopout.routine(f'Generated mesh with {nElems} cells') # hopout.sep() # hopout.info('GENERATE MESH DONE!') hopout.separator() diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index 8e72d76d..206ea56b 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -114,7 +114,7 @@ def MeshCartesian() -> meshio.Mesh: bcZones = [list() for _ in range(nZones)] for zone in range(nZones): - hopout.routine('Generating zone {}'.format(zone+1)) + hopout.routine(f'Generating zone {zone+1}') # check if corners are given in the input file if CountOption('Corner') > 0: @@ -136,7 +136,7 @@ def MeshCartesian() -> meshio.Mesh: np.array((X0[0]+DX[0], X0[1]+DX[1], X0[2]+DX[2])), np.array((X0[0], X0[1]+DX[1], X0[2]+DX[2])))) else: - hopout.error('No corners or DX vector given for zone {}'.format(zone+1)) + hopout.error(f'No corners or DX vector given for zone {zone+1}') nElems = GetIntArray( 'nElems' , number=zone) # Store the requested element types @@ -268,7 +268,7 @@ def MeshCartesian() -> meshio.Mesh: bcZones[zone] = [int(s) for s in GetIntArray('BCIndex')] # Assign the volume to a physical zone - _ = gmsh.model.addPhysicalGroup(3, [zone+1], name='Zone{}'.format(zone+1)) + _ = gmsh.model.addPhysicalGroup(3, [zone+1], name=f'Zone{zone+1}') # At this point, we can create a "Physical Group" corresponding # to the boundaries. This requires a synchronize call! @@ -322,7 +322,7 @@ def MeshCartesian() -> meshio.Mesh: if cast(np.ndarray, bcs[iBC].type)[3] > 0: pass elif cast(np.ndarray, bcs[iBC].type)[3] == 0: - hopout.error('BC "{}" has no periodic vector given, exiting...'.format(iBC + 1), traceback=True) + hopout.error(f'BC "{iBC + 1}" has no periodic vector given, exiting...', traceback=True) else: continue diff --git a/pyhope/mesh/mesh_external.py b/pyhope/mesh/mesh_external.py index 609a056a..4fba872c 100644 --- a/pyhope/mesh/mesh_external.py +++ b/pyhope/mesh/mesh_external.py @@ -96,7 +96,7 @@ def MeshExternal() -> meshio.Mesh: fnames[iFile] = os.path.abspath(os.path.join(os.path.dirname(prmfile), fname)) print(hopout.warn('Mesh not found in the CWD, but found in the prmfile directory.')) else: - hopout.error('Mesh file [󰇘]/{} does not exist'.format(os.path.basename(fname))) + hopout.error(f'Mesh file [󰇘]/{os.path.basename(fname)} does not exist') if not all(compatibleGMSH(fname) for fname in fnames): if any(compatibleGMSH(fname) for fname in fnames): @@ -131,7 +131,7 @@ def MeshExternal() -> meshio.Mesh: # If there are still files left, we have an unknown format if len(fnames) > 0: - hopout.error('Unknown file format {}, exiting...'.format(fnames)) + hopout.error(f'Unknown file format {fnames}, exiting...') # Regenerate the boundary conditions if mesh_vars.CGNS.regenerate_BCs: @@ -151,7 +151,7 @@ def MeshExternal() -> meshio.Mesh: vvs = recontruct_periodicity(mesh) hopout.routine('The following vectors were recovered:') for iVV, vv in enumerate(vvs): - hopout.printoption('vv[{}]'.format(iVV+1), '{0:}'.format(np.round(vv['Dir'], 6)), 'RECOVER') + hopout.printoption(f'vv[{iVV+1}]', '{0:}'.format(np.round(vv['Dir'], 6)), 'RECOVER') hopout.sep() # Flag mortar rebuild if merging multiple meshes diff --git a/pyhope/mesh/mesh_sort.py b/pyhope/mesh/mesh_sort.py index 52904105..6d30b5c0 100644 --- a/pyhope/mesh/mesh_sort.py +++ b/pyhope/mesh/mesh_sort.py @@ -289,8 +289,8 @@ def SortMeshByIJK() -> None: hopout.warning('Problem during sort elements by coordinate: nElems /= nElems_I * Elems_J * nElems_K') hopout.sep() - hopout.info(' Number of structured dirs : {}'.format(nStructDirs)) - hopout.info(' Number of elems [I,J,K] : {}'.format(nElemsIJK)) + hopout.info(f' Number of structured dirs : {nStructDirs}') + hopout.info(f' Number of elems [I,J,K] : {nElemsIJK}') bar = ProgressBar(value=len(elems), title='│ Preparing Elements', length=33) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 38bb5fc8..f23490ef 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -350,11 +350,11 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: # Try to convert the file automatically if not h5py.is_hdf5(fname): hopout.sep() - hopout.info('File {} is not in HDF5 CGNS format, converting ...'.format(os.path.basename(fname))) + hopout.info(f'File {os.path.basename(fname)} is not in HDF5 CGNS format, converting ...') tStart = time.time() _ = subprocess.run([f'adf2hdf {fname} {tname}'], check=True, shell=True, stdout=subprocess.DEVNULL) tEnd = time.time() - hopout.info('File {} converted HDF5 CGNS format [{:.2f} sec]'.format(os.path.basename(fname), tEnd - tStart)) + hopout.info(f'File {os.path.basename(fname)} converted HDF5 CGNS format [{tEnd - tStart:.2f} sec]') # Rest of this code operates on the converted file fname = tname diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index 3e9f0ef0..7aa67d4b 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -84,7 +84,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: for fnum, fname in enumerate(fnames): # Check if the file is using HDF5 format internally if not h5py.is_hdf5(fname): - hopout.error('[󰇘]/{} is not in HDF5 format, exiting...'.format(os.path.basename(fname))) + hopout.error(f'[󰇘]/{os.path.basename(fname)} is not in HDF5 format, exiting...') # Create a temporary directory and keep it existing until manually cleaned tfile = tempfile.NamedTemporaryFile(delete=False) @@ -95,7 +95,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: with h5py.File(tname, mode='r') as f: # Check if file contains the Hopr version if 'HoprVersion' not in f.attrs: - hopout.error('[󰇘]/{} does not contain the Hopr version, exiting...'.format(os.path.basename(fname))) + hopout.error(f'[󰇘]/{os.path.basename(fname)} does not contain the Hopr version, exiting...') # Read the globalNodeIDs nodeInfo = np.array(f['GlobalNodeIDs']) @@ -120,7 +120,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: hopout.sep() hopout.routine('The following vectors were found:') for iVV, vv in enumerate(mesh_vars.vvs): - hopout.printoption('vv[{}]'.format(iVV+1), '{0:}'.format(np.round(vv['Dir'], 6)), 'READ IN') + hopout.printoption(f'vv[{iVV+1}]', '{0:}'.format(np.round(vv['Dir'], 6)), 'READ IN') hopout.sep() # old hopr files might not contain the VV except KeyError: diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 2206d2d7..ea779986 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -91,7 +91,7 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: # Sanity check # > Check if the requested polynomial order is 1 if nGeo > 1: - hopout.error('nGeo = {} not supported for element splitting'.format(nGeo), traceback=True) + hopout.error(f'nGeo = {nGeo} not supported for element splitting', traceback=True) # > Check if the mesh contains any pyramids unsElems: Final[tuple] = ('pyramid') @@ -368,7 +368,7 @@ def tet_to_hex_points(order: int, z_split: bool = False) -> tuple[npt.NDArray, . ) case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order)) + hopout.error(f'Order {order} not supported for element splitting') @cache @@ -461,7 +461,7 @@ def prism_to_hex_points(order: int, z_split: bool = False) -> tuple[npt.NDArray, ) case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order)) + hopout.error(f'Order {order} not supported for element splitting') @cache diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index fb650aca..93812852 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -80,7 +80,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: if any(elemType % 10 != 8 for elemType in elemTypes) and nGeo > 4: hopout.error('Non-hexahedral elements are not supported for nGeo > 4, exiting...') if nGeo > 4: - hopout.error('nGeo = {} not supported for element splitting'.format(nGeo)) + hopout.error(f'nGeo = {nGeo} not supported for element splitting') hopout.info('Converting hexahedral elements to simplex elements') @@ -108,7 +108,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: case _: # tetrahedra elemNames[i] = elemTypeInam[elemTypes[i]][nGeo-2] except IndexError: - hopout.error('Element type {} not supported for nGeo = {}, exiting...'.format(elemTypes[i], nGeo)) + hopout.error(f'Element type {elemTypes[i]} not supported for nGeo = {nGeo}, exiting...') # Copy original points pointl = cast(list, mesh.points.tolist()) @@ -189,12 +189,12 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: # Sanity check if faceMap is None: - raise ValueError('Missing faceMap for element type {}'.format(elemType)) + raise ValueError(f'Missing faceMap for element type {elemType}') cdata = mesh.get_cells_type(mtype)[mcell] if split is None or faces is None: - hopout.error('Element type {} not supported for splitting'.format(elemTypes[iElem]), traceback=True) + hopout.error(f'Element type {elemTypes[iElem]} not supported for splitting', traceback=True) elemSplit = split(nGeo) @@ -373,7 +373,7 @@ def split_hex_to_tets(order: int) -> list[tuple]: case _: # Lazy-load local import import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) @cache @@ -399,7 +399,7 @@ def tetra_faces(order: int) -> tuple[npt.NDArray, ...]: np.array(( 1, 2, 3, *range( 7, 10) , *range(19, 22), *reversed(range(16, 19)), *range(25, 28)), dtype=int)) # noqa: E501 case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) @cache @@ -462,7 +462,7 @@ def split_hex_to_pyram(order: int) -> list[tuple[int, ...]]: 108, 172, 156, 116, 74, 73, 72, 71, 77, 76, 75, 78, 79, 171, 170, 154, 155, 121)] case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) @cache @@ -497,7 +497,7 @@ def pyram_faces(order: int) -> tuple[npt.NDArray, ...]: np.array(( 0, 1, 2, 3, *range(5, 17), *range(41, 50)), dtype=int)) case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) @cache @@ -568,7 +568,7 @@ def split_hex_to_prism(order: int) -> list[tuple[int, ...]]: case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) @cache @@ -611,7 +611,7 @@ def prism_faces(order: int) -> tuple[npt.NDArray, ...]: np.array(( 2, 0, 3, 5, *range(12, 15), *range(24, 27), *reversed(range(21, 24)), *reversed(range(30, 33)), *range(51, 60)), dtype=int)) # noqa: E501 case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) # Dummy function for hexahedral elements @@ -657,7 +657,7 @@ def hex_faces(order: int) -> tuple[npt.NDArray, ...]: np.array(( 4, 5, 6, 7, *range(20, 23), *range(23, 26), *range(26, 29) , *reversed(range(29, 32)), 89, *range(90, 93) , 93, *range(94, 97) , 97), dtype=int)) # noqa: E501 case _: import pyhope.output.output as hopout - hopout.error('Order {} not supported for element splitting'.format(order), traceback=True) + hopout.error(f'Order {order} not supported for element splitting', traceback=True) def appendBCSet(subFace: np.ndarray, diff --git a/pyhope/mesh/transform/mesh_transform.py b/pyhope/mesh/transform/mesh_transform.py index 3717560e..8fd8d166 100644 --- a/pyhope/mesh/transform/mesh_transform.py +++ b/pyhope/mesh/transform/mesh_transform.py @@ -229,7 +229,7 @@ def TransformMesh() -> None: # Continue with advanced transformations hopout.sep() hopout.routine('Performing advanced transformations') - hopout.routine(' Template: {}'.format(meshPostDeform)) + hopout.routine(f' Template: {meshPostDeform}') # Setup the transformation transformModule = LoadTemplate(meshPostDeform.strip().lower(), __file__, 'Post transformation') diff --git a/pyhope/output/output.py b/pyhope/output/output.py index ed230a8b..73a0db31 100644 --- a/pyhope/output/output.py +++ b/pyhope/output/output.py @@ -178,7 +178,7 @@ def separator(length: int = 46) -> None: def end(program: str, time: float, length: int = STD_LENGTH) -> None: print('┢' + '━'*(length-1)) - print('┃ {} completed in [{:.2f} sec]'.format(program, time)) + print(f'┃ {program} completed in [{time:.2f} sec]') print('┗' + '━'*(length-1)) @@ -217,7 +217,7 @@ def printoption(option: str, value: str, status: str, length: int = 31) -> None: """ try: if len(value) > length: - pvalue = '{}...'.format(value[:(length-3)]) + pvalue = f'{value[:(length-3)]}...' else: pvalue = value except TypeError: diff --git a/pyhope/readintools/commandline.py b/pyhope/readintools/commandline.py index 9d669450..e586b539 100644 --- a/pyhope/readintools/commandline.py +++ b/pyhope/readintools/commandline.py @@ -82,7 +82,7 @@ def __init__(self, argv, name: str, version: str, commit: Optional[str]) -> None # Check if we encountered a section if config.prms[key]['type'] == 'section': self.helpjoin(separator()) - self.helpjoin('! {}'.format(key)) + self.helpjoin(f'! {key}') self.helpjoin(separator()) continue diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index d040d1b8..68d31192 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -149,10 +149,10 @@ def CheckDefined(name: str, multiple: bool = False, init: bool = False) -> None: # - multiple parameter if init: if name in config.prms and not multiple: - hopout.error('Parameter "{}" already define and not a multiple option, exiting...'.format(name), traceback=True) + hopout.error(f'Parameter "{name}" already define and not a multiple option, exiting...', traceback=True) else: if name not in config.prms: - hopout.error('Parameter "{}" is not defined, exiting...'.format(name), traceback=True) + hopout.error(f'Parameter "{name}" is not defined, exiting...', traceback=True) def CheckUsed(name: str) -> None: @@ -162,7 +162,7 @@ def CheckUsed(name: str) -> None: # ------------------------------------------------------ if config.prms[name]['counter'] > 1 and not config.prms[name]['multiple']: - hopout.error('Parameter "{}" already used and not a multiple option, exiting...'.format(name), traceback=True) + hopout.error(f'Parameter "{name}" already used and not a multiple option, exiting...', traceback=True) def CheckType(name: str, calltype: str) -> None: @@ -172,7 +172,7 @@ def CheckType(name: str, calltype: str) -> None: # ------------------------------------------------------ if config.prms[name]['type'] is not calltype: - hopout.error('Call type of parameter "{}" does not match definition, exiting...'.format(name), traceback=True) + hopout.error(f'Call type of parameter "{name}" does not match definition, exiting...', traceback=True) def CheckDimension(name: str, result: int) -> None: @@ -182,7 +182,7 @@ def CheckDimension(name: str, result: int) -> None: # ------------------------------------------------------ if config.prms[name]['number'] != result: - hopout.error('Parameter "{}" has array length mismatch, exiting...'.format(name), traceback=True) + hopout.error(f'Parameter "{name}" has array length mismatch, exiting...', traceback=True) def CreateSection(string: str) -> None: @@ -355,7 +355,7 @@ def GetParam(name : str, # int2str has custom output if calltype != 'int2str': if calltype == 'bool': - hopout.printoption(name, '{0:}'.format(value), '*CUSTOM') + hopout.printoption(name, f'{value}', '*CUSTOM') else: hopout.printoption(name, value , '*CUSTOM') else: @@ -370,7 +370,7 @@ def GetParam(name : str, # int2str has custom output if calltype != 'int2str': if calltype == 'bool': - hopout.printoption(name, '{0:}'.format(value), 'DEFAULT') + hopout.printoption(name, f'{value}', 'DEFAULT') else: hopout.printoption(name, value , 'DEFAULT') else: @@ -432,7 +432,7 @@ def GetIntFromStr(name: str, default: Optional[str] = None, number: Optional[int result = int(result) - hopout.printoption(name, '{} [{}]'.format(result, mapping[result]), source) + hopout.printoption(name, f'{result} [{mapping[result]}]', source) return result @@ -640,7 +640,7 @@ def __enter__(self) -> ConfigParser: commit = process.communicate()[0].strip().decode('ascii') hopout.header(program, version, commit) - hopout.error('Parameter or mesh file [󰇘]/{} does not exist'.format(os.path.basename(self.input))) + hopout.error(f'Parameter or mesh file [󰇘]/{os.path.basename(self.input)} does not exist') # Check if input is mesh or parameter file parameter_mode = False @@ -655,7 +655,7 @@ def __enter__(self) -> ConfigParser: f.read() parameter_mode = True except UnicodeDecodeError: - hopout.error('Parameter or mesh file [󰇘]/{} are of unknown type'.format(os.path.basename(self.input))) + hopout.error(f'Parameter or mesh file [󰇘]/{os.path.basename(self.input)} are of unknown type') # Handle parameter data if parameter_mode: diff --git a/pyhope/script/pyhope_cli.py b/pyhope/script/pyhope_cli.py index 7acc6876..c1a37b1f 100755 --- a/pyhope/script/pyhope_cli.py +++ b/pyhope/script/pyhope_cli.py @@ -101,8 +101,7 @@ def main() -> None: # Check if there are unrecognized arguments if len(argv) >= 1: - print('{} expects exactly one parameter or HDF5-mesh file! Exiting ...' - .format(program)) + print(f'{program} expects exactly one parameter or HDF5-mesh file! Exiting ...') sys.exit() # Print banner From 0c893d2d8e2d8c3cfacb9d09571540793a16db19 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:11:22 +0100 Subject: [PATCH 02/59] Linting: Fix in-dict-keys (SIM118) --- pyhope/check/check_install.py | 2 +- pyhope/io/io_debug.py | 4 ++-- pyhope/io/io_xdmf.py | 2 +- pyhope/mesh/connect/connect.py | 2 +- pyhope/mesh/connect/connect_mortar.py | 4 ++-- pyhope/mesh/extrude/mesh_extrude.py | 8 ++++---- pyhope/mesh/fem/fem.py | 4 ++-- pyhope/mesh/mesh.py | 2 +- pyhope/mesh/mesh_common.py | 2 +- pyhope/mesh/mesh_duplicates.py | 2 +- pyhope/mesh/mesh_orient.py | 2 +- pyhope/mesh/mesh_sides.py | 10 +++++----- pyhope/mesh/reader/reader_gmsh.py | 14 +++++++------- pyhope/mesh/topology/mesh_serendipity.py | 2 +- pyhope/mesh/topology/mesh_splittohex.py | 8 ++++---- pyhope/mesh/topology/mesh_topology.py | 2 +- pyhope/readintools/readintools.py | 4 ++-- 17 files changed, 37 insertions(+), 37 deletions(-) diff --git a/pyhope/check/check_install.py b/pyhope/check/check_install.py index 4619a2ba..f98c0f66 100644 --- a/pyhope/check/check_install.py +++ b/pyhope/check/check_install.py @@ -374,7 +374,7 @@ def CheckInstall(path: Optional[str] = None) -> None: # Load the stats from the TOML file if h5stats is not None \ and tomlData is not None \ - and key in tomlData.keys(): # noqa: E271, E272 + and key in tomlData: # noqa: E271, E272 # Fallback tolerances: if 'GlobalNodeIDs' in key: # GlobalNodeIDs are susceptible to rounding issues diff --git a/pyhope/io/io_debug.py b/pyhope/io/io_debug.py index 8555df59..3c245071 100644 --- a/pyhope/io/io_debug.py +++ b/pyhope/io/io_debug.py @@ -249,7 +249,7 @@ def DebugIO() -> None: # Update points to unique first-order coords coords = mpoints[pMap] # Find the mapping from the cell keys to the elemtypes - elemOrder = [tInv[cb] for cb in elems.keys()] + elemOrder = [tInv[cb] for cb in elems] # Ensure cell_data lists are aligned to the actual cell block order used by meshio.Mesh elemdata = {k: [np.asarray(v[idx]) for idx in elemOrder] for k, v in elemdata.items()} @@ -274,7 +274,7 @@ def DebugIO() -> None: # del debugElem # Find the mapping from the side keys to the elemtypes - sideOrder = [sInv[cb] for cb in sides.keys()] + sideOrder = [sInv[cb] for cb in sides] # Ensure cell_data lists are aligned to the actual cell block order used by meshio.Mesh sidedata = {k: [np.asarray(v[idx]) for idx in sideOrder] for k, v in sidedata.items()} diff --git a/pyhope/io/io_xdmf.py b/pyhope/io/io_xdmf.py index fd0812ed..20e50af7 100644 --- a/pyhope/io/io_xdmf.py +++ b/pyhope/io/io_xdmf.py @@ -82,7 +82,7 @@ def XdmfWriterInit(self, for mesh in meshList: # Assign the correct subgrid name - if mesh.info is not None and 'name' in mesh.info.keys(): + if mesh.info is not None and 'name' in mesh.info: gridname = mesh.info['name'] else: gridname = 'Grid' diff --git a/pyhope/mesh/connect/connect.py b/pyhope/mesh/connect/connect.py index f488c0fc..9678f4e1 100644 --- a/pyhope/mesh/connect/connect.py +++ b/pyhope/mesh/connect/connect.py @@ -286,7 +286,7 @@ def ConnectMesh() -> None: # Consistency check for 2D boundary conditions prefixes: Final[tuple[str]] = ('quad', 'triangle') - if not any(k.startswith(p) for p in prefixes for k in cdict.keys()): # pragma: no cover + if not any(k.startswith(p) for p in prefixes for k in cdict): # pragma: no cover if bcs is not None and len(bcs) > 0: print(hopout.warn(f'Detected boundary conditions {[bc.name for bc in bcs]}')) hopout.error('Could not find any 2D boundary conditions, exiting...') diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index c00998b2..9dc27b7e 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -165,7 +165,7 @@ def ConnectMortar( nConnSide : list indexList.add(nConnID, targetNeighbors) # Obtain the target side IDs - targetSides: Final[list[int]] = [s for s in indexList.data.keys() if len(indexList.data[s]) > 0] + targetSides: Final[list[int]] = [s for s in indexList.data if len(indexList.data[s]) > 0] # Create a global offset manager. offsetManager: Final[LinkOffsetManager] = LinkOffsetManager() # Convert the sides to a red-black tree @@ -177,7 +177,7 @@ def ConnectMortar( nConnSide : list for targetID in targetSides: # Skip already connected sides # if indexList.data[targetID] == -1: - if targetID not in indexList.data.keys(): + if targetID not in indexList.data: continue # Get the target neighbors diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index ba05fe29..94e0b048 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -152,8 +152,8 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: csets_old.setdefault(frozenset(nodes), []).append(cname) # Create the element sets - meshcells = tuple((k, v) for k, v in mesh.cell_sets_dict.items() if any(key.startswith('tria') for key in v.keys()) - or any(key.startswith('quad') for key in v.keys())) + meshcells = tuple((k, v) for k, v in mesh.cell_sets_dict.items() if any(key.startswith('tria') for key in v) + or any(key.startswith('quad') for key in v)) match len(meshcells): case 0: @@ -248,7 +248,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: # Create the new faces subFaces = tuple(np.array(extElem)[face] for face in faces(nGeo)) - sidFaces = tuple((i, s) for i, s in enumerate(bcFaces) if ('side' in s.keys() and s['side'] == 'side')) + sidFaces = tuple((i, s) for i, s in enumerate(bcFaces) if ('side' in s and s['side'] == 'side')) for iFace, sidFace in sidFaces: subFace = subFaces[iFace] @@ -301,7 +301,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: # Temporarily assign mesh_vars.mesh with temporary_assign(mesh_vars, 'mesh', mesh): # Check if the surface normal of the first cell points outwards - for elemType in tuple(s for s in mesh.cells_dict.keys() if 'hexahedron' in s): + for elemType in tuple(s for s in mesh.cells_dict if 'hexahedron' in s): # Only check the first element, other elements get covered in OrientMesh ionodes: npt.NDArray = mesh.get_cells_type(elemType)[0] elemNames: Final[dict] = mesh_vars.ELEMTYPE.name diff --git a/pyhope/mesh/fem/fem.py b/pyhope/mesh/fem/fem.py index 8117ef6b..95c2a33e 100644 --- a/pyhope/mesh/fem/fem.py +++ b/pyhope/mesh/fem/fem.py @@ -173,7 +173,7 @@ def FEMConnect() -> None: # > are displaced by each periodic boundary condition. We build a simple, directed # > map for each BC that directly reflects the (source -> target) relationship in # > periNodes. We only want to map from negative to positive, thus keep the direction - periNames = sorted(list({bc for _, bc in periNodes.keys()})) + periNames = sorted(list({bc for _, bc in periNodes})) # This dictionary holds the directed mapping for each BC # > Key: Source node @@ -181,7 +181,7 @@ def FEMConnect() -> None: nodeMapBC: dict[str, dict[int, int]] = {bc: {int(n): int(p) for (n, b), p in periNodes.items() if b == bc} for bc in periNames} # For convenience, also build a set of all nodes that lie on any boundary - BCNodes = {int(node) for node, _ in periNodes.keys()} # noqa: E272 + BCNodes = {int(node) for node, _ in periNodes} # noqa: E272 BCNodes.update({int(peri) for peri in periNodes.values()}) # noqa: E272 # EDGE: Enumerate raw edges from the mesh diff --git a/pyhope/mesh/mesh.py b/pyhope/mesh/mesh.py index fa46cb66..14aac54b 100644 --- a/pyhope/mesh/mesh.py +++ b/pyhope/mesh/mesh.py @@ -214,7 +214,7 @@ def GenerateMesh() -> None: # Final count nElems = 0 for cellType in mesh.cells: - if any(s in cellType.type for s in mesh_vars.ELEMTYPE.type.keys()): + if any(s in cellType.type for s in mesh_vars.ELEMTYPE.type): nElems += mesh.get_cells_type(cellType.type).shape[0] hopout.routine(f'Generated mesh with {nElems} cells') diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index 7e3b6102..da50be2b 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -625,7 +625,7 @@ def count_elems(mesh: meshio.Mesh) -> int: nElems = 0 for _, elemType in enumerate(mesh.cells_dict.keys()): # Only consider three-dimensional types - if not any(s in elemType for s in elemTypeClass.type.keys()): + if not any(s in elemType for s in elemTypeClass.type): continue ioelems = mesh.get_cells_type(elemType) diff --git a/pyhope/mesh/mesh_duplicates.py b/pyhope/mesh/mesh_duplicates.py index 19970a18..2ab20b66 100644 --- a/pyhope/mesh/mesh_duplicates.py +++ b/pyhope/mesh/mesh_duplicates.py @@ -275,7 +275,7 @@ def EliminateDuplicates() -> None: # Also, remove near duplicate points # > Filter the valid three-dimensional cell types - valid_cells = tuple(cell for cell in cells if any(s in cell.type for s in mesh_vars.ELEMTYPE.type.keys())) + valid_cells = tuple(cell for cell in cells if any(s in cell.type for s in mesh_vars.ELEMTYPE.type)) # > Group by number of vertices per element to avoid ragged arrays groups = defaultdict(list) for cell in valid_cells: diff --git a/pyhope/mesh/mesh_orient.py b/pyhope/mesh/mesh_orient.py index 576e9597..351ac5ce 100644 --- a/pyhope/mesh/mesh_orient.py +++ b/pyhope/mesh/mesh_orient.py @@ -147,7 +147,7 @@ def OrientMesh() -> None: nElems = 0 passedTypes = [] - for elemType in mesh.cells_dict.keys(): + for elemType in mesh.cells_dict: # Only consider three-dimensional types if not any(s in elemType for s in elemKeys): continue diff --git a/pyhope/mesh/mesh_sides.py b/pyhope/mesh/mesh_sides.py index e5fe7fe1..9f337e1d 100644 --- a/pyhope/mesh/mesh_sides.py +++ b/pyhope/mesh/mesh_sides.py @@ -64,9 +64,9 @@ def GenerateSides() -> None: sides = mesh_vars.sides totalElems = 0 - for elemType in mesh.cells_dict.keys(): + for elemType in mesh.cells_dict: # Only consider three-dimensional types - if not any(s in elemType for s in mesh_vars.ELEMTYPE.type.keys()): + if not any(s in elemType for s in mesh_vars.ELEMTYPE.type): continue totalElems += mesh.get_cells_type(elemType).shape[0] @@ -76,9 +76,9 @@ def GenerateSides() -> None: bar = ProgressBar(value=totalElems, title='│ Processing Elements', length=33, chunk=chunk) # Loop over all element types - for elemType in mesh.cells_dict.keys(): + for elemType in mesh.cells_dict: # Only consider three-dimensional types - if not any(s in elemType for s in mesh_vars.ELEMTYPE.type.keys()): + if not any(s in elemType for s in mesh_vars.ELEMTYPE.type): continue # Get the elements @@ -92,7 +92,7 @@ def GenerateSides() -> None: elemSet: list[Union[None, int]] = [None for _ in range(nIOElems)] for key, val in iocsets.items(): - if elemType not in val.keys(): + if elemType not in val: continue # Extract the zoneID diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index f23490ef..b5067e53 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -254,7 +254,7 @@ def ReadGMSH(fnames: list) -> meshio.Mesh: # Check whether the mesh contains high-order elements and nGeo is set to 1 if not mesh_vars.already_curved or mesh_vars.nGeo == 1: - for elemtype in mesh.cells_dict.keys(): + for elemtype in mesh.cells_dict: if elemtype in mesh_vars.ELEMTYPE.name and mesh_vars.ELEMTYPE.name[elemtype] > 200: hopout.error('High-order elements detected in the mesh but MeshIsAlreadyCurved=F or nGeo is set to 1, exiting...') @@ -363,10 +363,10 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: shutil.copyfile(fname, tname) with h5py.File(fname, mode='r') as f: - if 'CGNSLibraryVersion' not in f.keys(): + if 'CGNSLibraryVersion' not in f: hopout.error('CGNS file does not contain library version header') - key = [s for s in f.keys() if s.strip() not in ('format', 'hdf5version', 'CGNSLibraryVersion')] + key = [s for s in f if s.strip() not in ('format', 'hdf5version', 'CGNSLibraryVersion')] match len(key): case 0: hopout.error('Object [Base] does not exist in CGNS file') @@ -377,14 +377,14 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: case _: hopout.error('More than one object [Base] exists in CGNS file') - for baseZone in base.keys(): + for baseZone in base: # Ignore the base dataset if baseZone.strip() == 'data': continue zone = cast(h5py.Group, base[baseZone]) # Check if the zone contains BCs - if 'ZoneBC' not in zone.keys(): + if 'ZoneBC' not in zone: continue zonedata = cast(h5py.Dataset, zone[' data']) @@ -433,7 +433,7 @@ def BCCGNS_Unstructured( mesh: meshio.Mesh, bpoints = np.column_stack([zone['GridCoordinates'][f'Coordinate{axis}'][' data'][:].astype(float) for axis in 'XYZ']) # Loop over all BCs - zoneBCs = [s for s in cast(h5py.Group, zone['ZoneBC']).keys() if s.strip() != 'innerfaces'] + zoneBCs = [s for s in cast(h5py.Group, zone['ZoneBC']) if s.strip() != 'innerfaces'] cellsets = mesh.cell_sets # Convert the cellsets to a list of lists for easier manipulation for k, v in cellsets.items(): @@ -521,7 +521,7 @@ def BCCGNS_Unstructured( mesh: meshio.Mesh, # Collect all element sections present in the zone elemSections = [] - for key in zone.keys(): + for key in zone: if not isinstance(zone[key], h5py.Group): continue if 'ElementConnectivity' not in zone[key] or 'ElementRange' not in zone[key]: diff --git a/pyhope/mesh/topology/mesh_serendipity.py b/pyhope/mesh/topology/mesh_serendipity.py index b35f9a63..45506cdc 100644 --- a/pyhope/mesh/topology/mesh_serendipity.py +++ b/pyhope/mesh/topology/mesh_serendipity.py @@ -53,7 +53,7 @@ def convertSerendipityToFullLagrange(mesh: meshio.Mesh) -> meshio.Mesh: # Check the mesh contains second-order incomplete elements serendipityElems = ['quad8', 'hexahedron20', 'wedge15', 'pyramid13'] - if not any(s for s in mesh.cells_dict.keys() if s in serendipityElems): + if not any(s for s in mesh.cells_dict if s in serendipityElems): return mesh hopout.routine('Converting serendipity to full langrange mesh') diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index ea779986..00aa562a 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -95,8 +95,8 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: # > Check if the mesh contains any pyramids unsElems: Final[tuple] = ('pyramid') - if any(s.startswith(x) for x in unsElems for s in cdict.keys()): - unsupported = [s for s in cdict.keys() if any(s.startswith(x) for x in unsElems)] + if any(s.startswith(x) for x in unsElems for s in cdict): + unsupported = [s for s in cdict if any(s.startswith(x) for x in unsElems)] hopout.error('Element type[s] "{}" are not supported for splitting, exiting...'.format(', '.join(unsupported))) faceType = ['triangle' , 'quad' ] @@ -159,8 +159,8 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: hexBCQuads = set() if splitToHexZ: unszElems = ('tetrahedron', 'pyramid') - if any(s.startswith(x) for x in unszElems for s in cdict.keys()): - unsupported = [s for s in cdict.keys() if any(s.startswith(x) for x in unszElems)] + if any(s.startswith(x) for x in unszElems for s in cdict): + unsupported = [s for s in cdict if any(s.startswith(x) for x in unszElems)] hopout.error('Element type[s] "{}" are not supported for z-splitting, exiting...'.format(', '.join(unsupported))) # Inquire if elements should be split in z-director or we should build mortar interfaces diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 93812852..9768366f 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -161,7 +161,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: csets_lst = {} # Create the element sets - meshcells = tuple((k, v) for k, v in mesh.cell_sets_dict.items() if any(key.startswith('hexahedron') for key in v.keys())) + meshcells = tuple((k, v) for k, v in mesh.cell_sets_dict.items() if any(key.startswith('hexahedron') for key in v)) # If meshcells is empty, we fake it assign it to Zone1 if len(meshcells) == 0: diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 68d31192..895c947a 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -423,7 +423,7 @@ def GetIntFromStr(name: str, default: Optional[str] = None, number: Optional[int except (ValueError, TypeError): result = options.get(str(value).lower()) - if result is None or result not in mapping.keys(): # pragma: no cover + if result is None or result not in mapping: # pragma: no cover outStr = ', '.join([f'{k} [{v}]' for k, v in mapping.items()]) print() print(hopout.warn(f'Allowed values for parameter "{name}":')) @@ -720,7 +720,7 @@ def __enter__(self) -> ConfigParser: # Parse configation file either from read in parameter file or # recovered from a given mesh file - config.std_length = max(len(s) for s in config.prms.keys()) + config.std_length = max(len(s) for s in config.prms) config.std_length = max(32, config.std_length+1) # Loop over all objects and check if they are provided From f2a14a5fe15ec55f91799071eeb67d7bed680e34 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:12:10 +0100 Subject: [PATCH 03/59] Linting: Fix useless-return (PLR1711) --- pyhope/readintools/commandline.py | 1 - pyhope/readintools/readintools.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/pyhope/readintools/commandline.py b/pyhope/readintools/commandline.py index e586b539..13bbb450 100644 --- a/pyhope/readintools/commandline.py +++ b/pyhope/readintools/commandline.py @@ -102,7 +102,6 @@ def __init__(self, argv, name: str, version: str, commit: Optional[str]) -> None self.helpjoin(f'{key:<{PAR_LENGTH}} = {default:>{DEF_LENGTH}} ! {help}') - return None def __enter__(self) -> tuple[Namespace, list]: # Setup an argument parser and add know arguments diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 895c947a..525f5c6c 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -128,7 +128,6 @@ class DefineConfig: def __init__(self) -> None: # Create an empty config dictionary self.dict = dict() - return None def __enter__(self) -> dict: return self.dict @@ -494,7 +493,6 @@ def __init__(self, input: str) -> None: # define allowed comments self.sym_comm = ('#', ';', '!') - return None def _read_file(self) -> list: """ Read the parameter file and replace DEFVAR variables From 96e8082058aea8f50ea3b656638c84d78993b088 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:12:54 +0100 Subject: [PATCH 04/59] Linting: Fix unnecessary-class-parentheses (UP039) --- pyhope/common/common_vars.py | 4 ++-- pyhope/readintools/readintools.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyhope/common/common_vars.py b/pyhope/common/common_vars.py index 3ad6e444..570da32b 100644 --- a/pyhope/common/common_vars.py +++ b/pyhope/common/common_vars.py @@ -70,7 +70,7 @@ def getinstance(): @singleton -class Common(): +class Common: def __init__(self: Self) -> None: self._program: Final[str] = self.__program__ self._version: Final = self.__version__ @@ -138,7 +138,7 @@ def commit(self) -> str: @final -class Gitlab(): +class Gitlab: # Gitlab "python-gmsh" access LIB_GITLAB: str = 'gitlab.iag.uni-stuttgart.de' # LIB_PROJECT = 'libs/python-gmsh' diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 525f5c6c..935a7bf9 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -479,7 +479,7 @@ def GetIntArray(name: str, default: Optional[str] = None, number: Optional[int] # ================================================================================================================================== @final -class ReadConfig(): +class ReadConfig: """ Read an HOPR parameter file This file is meant to remain compatible to the HOPR parameter file From 2cf3d00ee771c6a09ac28fb7054628993aaea366 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:16:19 +0100 Subject: [PATCH 05/59] Linting: Fix unnecessary-assign (RET504) --- pyhope/gmsh/gmsh_install.py | 3 +-- pyhope/mesh/connect/connect_mortar.py | 9 ++++----- pyhope/mesh/mesh_common.py | 6 ++---- pyhope/mesh/mesh_duplicates.py | 3 +-- pyhope/mesh/mesh_orient.py | 3 +-- pyhope/mesh/reader/reader_gmsh.py | 16 ++++++---------- pyhope/readintools/readintools.py | 3 +-- 7 files changed, 16 insertions(+), 27 deletions(-) diff --git a/pyhope/gmsh/gmsh_install.py b/pyhope/gmsh/gmsh_install.py index 2944c672..e85f7ed5 100644 --- a/pyhope/gmsh/gmsh_install.py +++ b/pyhope/gmsh/gmsh_install.py @@ -60,8 +60,7 @@ def PkgsMetaVersion(pkgs) -> Optional[str]: """ Check the package version """ try: - version = metadata.version(pkgs) - return version + return metadata.version(pkgs) except metadata.PackageNotFoundError: return None diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index 9dc27b7e..5f442c83 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -613,11 +613,10 @@ def build_edges(corners: npt.NDArray, points: npt.NDArray) -> tuple: if len(corners) < 4 or len(points) < 4: return () - edges = ((corners[0], corners[1], norm(np.array(points[0]) - np.array(points[1]))), # Edge between points 0 and 1 - (corners[1], corners[2], norm(np.array(points[1]) - np.array(points[2]))), # Edge between points 1 and 2 - (corners[2], corners[3], norm(np.array(points[2]) - np.array(points[3]))), # Edge between points 2 and 3 - (corners[3], corners[0], norm(np.array(points[3]) - np.array(points[0])))) # Edge between points 3 and 0 - return edges + return ((corners[0], corners[1], norm(np.array(points[0]) - np.array(points[1]))), # Edge between points 0 and 1 + (corners[1], corners[2], norm(np.array(points[1]) - np.array(points[2]))), # Edge between points 1 and 2 + (corners[2], corners[3], norm(np.array(points[2]) - np.array(points[3]))), # Edge between points 2 and 3 + (corners[3], corners[0], norm(np.array(points[3]) - np.array(points[0])))) # Edge between points 3 and 0 # INFO: Cached version diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index da50be2b..de650071 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -337,8 +337,7 @@ def FaceOrdering(side_type: str, order: int, dtype=np.int32) -> npt.NDArray: interior = grid[1:n, 1:n].flatten() # Assemble ordering: corners, edges, interior # ordering = np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior)) - ordering = np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior), dtype=dtype) - return ordering + return np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior), dtype=dtype) elif side_type.lower() == 'triangle': # Total nodes on face: (nGeo+1)*(nGeo+2)//2 @@ -449,8 +448,7 @@ def sidetovol2(N: int, flip: int, face: str, elemType: Union[str, int], dtype=np # idx_arr will have shape (0:N, 0:N, 3) idx_arr = vec_cgns(R, pq[0], pq[1]) # Use the computed indices from idx_arr to index mapLin - map = mapLin[idx_arr[..., 0], idx_arr[..., 1], idx_arr[..., 2]] - return map + return mapLin[idx_arr[..., 0], idx_arr[..., 1], idx_arr[..., 2]] @cache diff --git a/pyhope/mesh/mesh_duplicates.py b/pyhope/mesh/mesh_duplicates.py index 2ab20b66..6344d9f1 100644 --- a/pyhope/mesh/mesh_duplicates.py +++ b/pyhope/mesh/mesh_duplicates.py @@ -153,9 +153,8 @@ def _findPointsTol(points: npt.NDArray, tol: float, method: str = 'union_find') repLabel = np.full(components, nPoints, dtype=int) # Assign each point its component representative np.minimum.at(repLabel, labels, np.arange(nPoints, dtype=int)) - repsPoint = repLabel[labels] + return repLabel[labels] - return repsPoint def EliminateDuplicates() -> None: diff --git a/pyhope/mesh/mesh_orient.py b/pyhope/mesh/mesh_orient.py index 351ac5ce..cd5f5d93 100644 --- a/pyhope/mesh/mesh_orient.py +++ b/pyhope/mesh/mesh_orient.py @@ -71,8 +71,7 @@ def eval_dotprod(fpoints, nVecFace) -> np.float64: # Dot product and check if normal points outwards # > Manually compute dot product - dotprod = nVecFace[0]*normal[0] + nVecFace[1]*normal[1] + nVecFace[2]*normal[2] - return dotprod + return nVecFace[0]*normal[0] + nVecFace[1]*normal[1] + nVecFace[2]*normal[2] def check_orientation(ionodes : npt.NDArray, diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index b5067e53..77cfaec3 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -614,11 +614,9 @@ def BCCGNS_Unstructured( mesh: meshio.Mesh, for k, v in cellsets.items(): csets[k] = [np.array(s, dtype=int) for s in v] - mesh = meshio.Mesh(points = points, # noqa: E251 - cells = cells, # noqa: E251 - cell_sets = csets) # noqa: E251 - - return mesh + return meshio.Mesh(points = points, # noqa: E251 + cells = cells, # noqa: E251 + cell_sets = csets) # noqa: E251 def BCCGNS_Structured(mesh: meshio.Mesh, @@ -723,8 +721,6 @@ def BCCGNS_Structured(mesh: meshio.Mesh, for k, v in cellsets.items(): csets[k] = [np.array(s, dtype=int) for s in v] - mesh = meshio.Mesh(points = points, # noqa: E251 - cells = cells, # noqa: E251 - cell_sets = csets) # noqa: E251 - - return mesh + return meshio.Mesh(points = points, # noqa: E251 + cells = cells, # noqa: E251 + cell_sets = csets) # noqa: E251 diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 935a7bf9..8521f101 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -381,8 +381,7 @@ def GetParam(name : str, def GetStr(name: str, default: Optional[str] = None, number: Optional[int] = None) -> str: - value = GetParam(name=name, default=default, number=number, calltype='str') - return value + return GetParam(name=name, default=default, number=number, calltype='str') def GetReal(name: str, default: Optional[str] = None, number: Optional[int] = None) -> float: From d7dd94ca8de506231dec1d8375c1916fbe3fdbef Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:25:04 +0100 Subject: [PATCH 06/59] Linting: Fix unnecessary-collection-call (C408) --- pyhope/io/io_debug.py | 26 +++---- pyhope/mesh/mesh_builtin.py | 6 +- pyhope/mesh/mesh_external.py | 8 +- pyhope/mesh/reader/reader_hopr.py | 4 +- pyhope/mesh/topology/mesh_serendipity.py | 4 +- pyhope/readintools/readintools.py | 96 ++++++++++++------------ 6 files changed, 72 insertions(+), 72 deletions(-) diff --git a/pyhope/io/io_debug.py b/pyhope/io/io_debug.py index 3c245071..47c57f26 100644 --- a/pyhope/io/io_debug.py +++ b/pyhope/io/io_debug.py @@ -153,24 +153,24 @@ def DebugIO() -> None: # Create ordered mapping from first-order sides to high-order sides sypes = list(sidetypes) - elemdata: dict[str, list] = {'ElemID' : [list() for _ in range(len(types))], - 'ElemType': [list() for _ in range(len(types))], - 'ElemZone': [list() for _ in range(len(types))], + elemdata: dict[str, list] = {'ElemID' : [[] for _ in range(len(types))], + 'ElemType': [[] for _ in range(len(types))], + 'ElemZone': [[] for _ in range(len(types))], } # (Optional:) Add Jacobians if melems and (getattr(melems[0], 'jacobian', None) is not None): - elemdata.update({'ElemJacobian': [list() for _ in range(len(types))]}) + elemdata.update({'ElemJacobian': [[] for _ in range(len(types))]}) # (Optional:) Add IJK sorting if hasIJK: - elemdata.update({'Elem_I' : [list() for _ in range(len(types))]}) - elemdata.update({'Elem_J' : [list() for _ in range(len(types))]}) - elemdata.update({'Elem_K' : [list() for _ in range(len(types))]}) - - sidedata: dict[str, list] = {'ElemID' : [list() for _ in range(len(sypes))], - 'BCID' : [list() for _ in range(len(sypes))], - 'BCType' : [list() for _ in range(len(sypes))], - 'BCState' : [list() for _ in range(len(sypes))], - 'BCAlpha' : [list() for _ in range(len(sypes))], + elemdata.update({'Elem_I' : [[] for _ in range(len(types))]}) + elemdata.update({'Elem_J' : [[] for _ in range(len(types))]}) + elemdata.update({'Elem_K' : [[] for _ in range(len(types))]}) + + sidedata: dict[str, list] = {'ElemID' : [[] for _ in range(len(sypes))], + 'BCID' : [[] for _ in range(len(sypes))], + 'BCType' : [[] for _ in range(len(sypes))], + 'BCState' : [[] for _ in range(len(sypes))], + 'BCAlpha' : [[] for _ in range(len(sypes))], } nodedata: dict[str, list] = {} diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index 206ea56b..75753486 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -111,7 +111,7 @@ def MeshCartesian() -> meshio.Mesh: # > https://gitlab.onelab.info/gmsh/gmsh/-/issues/2836 gmsh.model.add('Domain') gmsh.model.set_current('Domain') - bcZones = [list() for _ in range(nZones)] + bcZones = [[] for _ in range(nZones)] for zone in range(nZones): hopout.routine(f'Generating zone {zone+1}') @@ -292,10 +292,10 @@ def MeshCartesian() -> meshio.Mesh: nVVs = CountOption('vv') if nVVs > 0: hopout.sep() - mesh_vars.vvs = [dict() for _ in range(nVVs)] + mesh_vars.vvs = [{} for _ in range(nVVs)] vvs = mesh_vars.vvs for iVV, _ in enumerate(vvs): - vvs[iVV] = dict() + vvs[iVV] = {} vvs[iVV]['Dir'] = GetRealArray('vv', number=iVV) # Flatten the BC array, the surface numbering follows from the 2-D ordering diff --git a/pyhope/mesh/mesh_external.py b/pyhope/mesh/mesh_external.py index 4fba872c..f6c383a3 100644 --- a/pyhope/mesh/mesh_external.py +++ b/pyhope/mesh/mesh_external.py @@ -76,16 +76,16 @@ def MeshExternal() -> meshio.Mesh: bc.type = GetIntArray('BoundaryType', number=iBC) # noqa: E251 nVVs = CountOption('vv') - mesh_vars.vvs = [dict() for _ in range(nVVs)] + mesh_vars.vvs = [{} for _ in range(nVVs)] vvs = mesh_vars.vvs if len(vvs) > 0: hopout.sep() for iVV, _ in enumerate(vvs): - vvs[iVV] = dict() + vvs[iVV] = {} vvs[iVV]['Dir'] = GetRealArray('vv', number=iVV) # Load the mesh(es) - mesh = meshio.Mesh(np.array(()), dict()) + mesh = meshio.Mesh(np.array(()), {}) fnames = [GetStr('Filename', number=i) for i in range(CountOption('Filename'))] # Check whether mesh file exists in the current directory or in the same directory @@ -147,7 +147,7 @@ def MeshExternal() -> meshio.Mesh: print(hopout.warn('Periodicity vectors neither defined in parameter file nor ' 'in the given mesh file. Reconstructing the vectors from BCs!')) # Get max number of periodic alphas - mesh_vars.vvs = [dict() for _ in range(int(np.max([np.abs(cast(np.ndarray, bc.type)[3]) for bc in bcs])))] + mesh_vars.vvs = [{} for _ in range(int(np.max([np.abs(cast(np.ndarray, bc.type)[3]) for bc in bcs])))] vvs = recontruct_periodicity(mesh) hopout.routine('The following vectors were recovered:') for iVV, vv in enumerate(vvs): diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index 7aa67d4b..8ea11334 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -110,9 +110,9 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: if len(mesh_vars.vvs) == 0: try: vvs = np.array(f['VV']) - mesh_vars.vvs = [dict() for _ in range(vvs.shape[0])] + mesh_vars.vvs = [{} for _ in range(vvs.shape[0])] for iVV, _ in enumerate(mesh_vars.vvs): - mesh_vars.vvs[iVV] = dict() + mesh_vars.vvs[iVV] = {} mesh_vars.vvs[iVV]['Dir'] = vvs[iVV] # Output vectors print(hopout.warn('Periodicity vectors not defined in parameter file. ' diff --git a/pyhope/mesh/topology/mesh_serendipity.py b/pyhope/mesh/topology/mesh_serendipity.py index 45506cdc..f3a395b2 100644 --- a/pyhope/mesh/topology/mesh_serendipity.py +++ b/pyhope/mesh/topology/mesh_serendipity.py @@ -88,7 +88,7 @@ def convertSerendipityToFullLagrange(mesh: meshio.Mesh) -> meshio.Mesh: nFaces = len(faces) N = [np.array(()) for _ in range(nFaces + 1)] - faceNodes = [list() for _ in faces] # noqa: E272 + faceNodes = [[] for _ in faces] # noqa: E272 # preallocate the arrays for the new points and elements nPoints_old = len(points) @@ -145,7 +145,7 @@ def convertSerendipityToFullLagrange(mesh: meshio.Mesh) -> meshio.Mesh: nFaces = len(faces) N = [np.array(()) for _ in range(nFaces + 1)] - faceNodes = [list() for _ in faces] # noqa: E272 + faceNodes = [[] for _ in faces] # noqa: E272 # preallocate the arrays for the new points and elements nPoints_old = len(points) diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 8521f101..a8462812 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -127,7 +127,7 @@ class DefineConfig: """ def __init__(self) -> None: # Create an empty config dictionary - self.dict = dict() + self.dict = {} def __enter__(self) -> dict: return self.dict @@ -190,7 +190,7 @@ def CreateSection(string: str) -> None: # ------------------------------------------------------ CheckDefined(string, multiple=False, init=True) - config.prms[string] = dict(type='section', name=string) + config.prms[string] = {'type': 'section', 'name': string} def CreateStr(string: str, help: Optional[str] = None, default: Optional[str] = None, multiple: bool = False) -> None: @@ -199,12 +199,12 @@ def CreateStr(string: str, help: Optional[str] = None, default: Optional[str] = # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='str', - name=string, - help=help, - default=str(default), - counter=0, - multiple=multiple) + config.prms[string] = {'type': 'str', + 'name': string, + 'help': help, + 'default': str(default), + 'counter': 0, + 'multiple': multiple} def CreateReal(string: str, help: Optional[str] = None, default: Optional[float] = None, multiple=False) -> None: @@ -213,12 +213,12 @@ def CreateReal(string: str, help: Optional[str] = None, default: Optional[float] # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='real', - name=string, - help=help, - default=str(default), - counter=0, - multiple=multiple) + config.prms[string] = {'type': 'real', + 'name': string, + 'help': help, + 'default': str(default), + 'counter': 0, + 'multiple': multiple} def CreateInt(string: str, help: Optional[str] = None, default: Optional[int] = None, multiple=False) -> None: @@ -227,12 +227,12 @@ def CreateInt(string: str, help: Optional[str] = None, default: Optional[int] = # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='int', - name=string, - help=help, - default=str(default), - counter=0, - multiple=multiple) + config.prms[string] = {'type': 'int', + 'name': string, + 'help': help, + 'default': str(default), + 'counter': 0, + 'multiple': multiple} def CreateLogical(string: str, help: Optional[str] = None, default: Optional[bool] = None, multiple=False) -> None: @@ -241,12 +241,12 @@ def CreateLogical(string: str, help: Optional[str] = None, default: Optional[boo # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='bool', - name=string, - help=help, - default=default, - counter=0, - multiple=multiple) + config.prms[string] = {'type': 'bool', + 'name': string, + 'help': help, + 'default': default, + 'counter': 0, + 'multiple': multiple} def CreateIntFromString(string: str, help: Optional[str] = None, default: Optional[str] = None, multiple=False) -> None: @@ -255,14 +255,14 @@ def CreateIntFromString(string: str, help: Optional[str] = None, default: Option # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='int2str', - name=string, - mapping=dict(), - help=help, - default=default, - counter=0, - source=None, - multiple=multiple) + config.prms[string] = {'type': 'int2str', + 'name': string, + 'mapping': {}, + 'help': help, + 'default': default, + 'counter': 0, + 'source': None, + 'multiple': multiple} def CreateIntOption(string: str, name, number) -> None: @@ -281,13 +281,13 @@ def CreateRealArray(string: str, nReals, help: Optional[str] = None, default: Op # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='realarray', - number=nReals, - name=string, - help=help, - default=default, - counter=0, - multiple=multiple) + config.prms[string] = {'type': 'realarray', + 'number': nReals, + 'name': string, + 'help': help, + 'default': default, + 'counter': 0, + 'multiple': multiple} def CreateIntArray(string: str, nInts, help: Optional[str] = None, default: Optional[str] = None, multiple=False) -> None: @@ -296,13 +296,13 @@ def CreateIntArray(string: str, nInts, help: Optional[str] = None, default: Opti # ------------------------------------------------------ CheckDefined(string, multiple, init=True) - config.prms[string] = dict(type='intarray', - number=nInts, - name=string, - help=help, - default=default, - counter=0, - multiple=multiple) + config.prms[string] = {'type': 'intarray', + 'number': nInts, + 'name': string, + 'help': help, + 'default': default, + 'counter': 0, + 'multiple': multiple} # ================================================================================================================================== From 23498b3be64daf55d0791c8e15fb65c1dad258d3 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:27:15 +0100 Subject: [PATCH 07/59] Linting: Fix printf-string-formatting (UP031) --- pyhope/readintools/readintools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index a8462812..aadd2cec 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -83,7 +83,7 @@ def strToBool(val: Union[int, bool, str]) -> bool: # From distutils.util.strtob elif val in ('n', 'no' , 'f', 'false', 'off', '0'): # noqa: E271 return False else: - raise ValueError('invalid truth value %r' % (val,)) + raise ValueError(f'invalid truth value {val!r}') def strToFloatOrPi(helpstr: str) -> float: @@ -105,7 +105,7 @@ def strToFloatOrPi(helpstr: str) -> float: value = float(splitstr[0]) case _: - raise ValueError('Failed to parse input string %s' % (helpstr)) + raise ValueError(f'Failed to parse input string {helpstr}') return value From d537b50f7ad509130234e04255393ad4b641ef73 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:32:10 +0100 Subject: [PATCH 08/59] Linting: Fix non-pep585-annotation (UP006) --- pyhope/common/common_tools.py | 4 ++-- pyhope/io/formats/meshio.py | 9 ++++----- pyhope/io/formats/vtk.py | 3 +-- pyhope/mesh/connect/connect_rbtree.py | 14 +++++++------- pyhope/mesh/elements/elements_ordering.py | 9 ++++----- pyhope/mesh/elements/elements_shapefunctions.py | 4 ++-- pyhope/mesh/fem/fem.py | 4 ++-- pyhope/mesh/mesh_common.py | 4 ++-- pyhope/mesh/mesh_duplicates.py | 8 ++++---- pyhope/mesh/mesh_sort.py | 4 ++-- pyhope/mesh/mesh_vars.py | 16 ++++++++-------- pyhope/mesh/sort/sort_hilbert.py | 8 ++++---- pyhope/mesh/topology/mesh_splittohex.py | 8 ++++---- pyhope/meshio/meshio_convert.py | 16 ++++++++-------- pyhope/meshio/meshio_nodes.py | 3 +-- pyhope/meshio/meshio_ordering.py | 12 ++++++------ 16 files changed, 61 insertions(+), 65 deletions(-) diff --git a/pyhope/common/common_tools.py b/pyhope/common/common_tools.py index b6841823..508725e0 100644 --- a/pyhope/common/common_tools.py +++ b/pyhope/common/common_tools.py @@ -29,7 +29,7 @@ # from sortedcontainers import SortedDict from collections import defaultdict from contextlib import contextmanager -from typing import Final, Tuple +from typing import Final # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -78,7 +78,7 @@ def time_function(func, *args, **kwargs) -> float: # pragma: no cover return result -def allocate_or_resize( dict: dict, key: str, shape: Tuple[int, int]) -> Tuple[dict, int]: +def allocate_or_resize( dict: dict, key: str, shape: tuple[int, int]) -> tuple[dict, int]: """ Allocate or resize a numpy array in a dictionary. """ offset = 0 diff --git a/pyhope/io/formats/meshio.py b/pyhope/io/formats/meshio.py index 1a732fc7..c28c7284 100644 --- a/pyhope/io/formats/meshio.py +++ b/pyhope/io/formats/meshio.py @@ -27,7 +27,6 @@ # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations from functools import cache -from typing import Tuple # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -181,7 +180,7 @@ def facePointMESHIO(start: int, end: int, face: int, pos: int) -> npt.NDArray: @cache -def HEXAMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: +def HEXAMAPMESHIO(order: int) -> tuple[npt.NDArray, npt.NDArray]: """ MESHIO -> IJK ordering for high-order hexahedrons > HEXTEN : np.ndarray # MESHIO <-> IJK ordering for high-order hexahedrons (1D, tensor-product style) > HEXMAP : np.ndarray # MESHIO <-> IJK ordering for high-order hexahedrons (3D mapping) @@ -267,7 +266,7 @@ def HEXAMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: @cache -def PRISMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: +def PRISMAPMESHIO(order: int) -> tuple[npt.NDArray, npt.NDArray]: """ MESHIO -> IJK ordering for high-order prisms > HEXTEN : np.ndarray # MESHIO <-> IJK ordering for high-order prisms (1D, tensor-product style) > HEXMAP : np.ndarray # MESHIO <-> IJK ordering for high-order prisms (3D mapping) @@ -410,7 +409,7 @@ def PRISMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: @cache -def PYRAMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: +def PYRAMAPMESHIO(order: int) -> tuple[npt.NDArray, npt.NDArray]: """ MESHIO -> IJK ordering for high-order pyramids > HEXTEN : np.ndarray # MESHIO <-> IJK ordering for high-order pyramids (1D, tensor-product style) > HEXMAP : np.ndarray # MESHIO <-> IJK ordering for high-order pyramids (3D mapping) @@ -537,7 +536,7 @@ def PYRAMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: @cache -def TETRMAPMESHIO(order: int) -> Tuple[npt.NDArray, npt.NDArray]: +def TETRMAPMESHIO(order: int) -> tuple[npt.NDArray, npt.NDArray]: """ MESHIO -> IJK ordering for high-order tetrahedrons > HEXTEN : np.ndarray # MESHIO <-> IJK ordering for high-order tetrahedrons (1D, tensor-product style) > HEXMAP : np.ndarray # MESHIO <-> IJK ordering for high-order tetrahedrons (3D mapping) diff --git a/pyhope/io/formats/vtk.py b/pyhope/io/formats/vtk.py index c460f88a..bb001fd2 100644 --- a/pyhope/io/formats/vtk.py +++ b/pyhope/io/formats/vtk.py @@ -27,7 +27,6 @@ # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations from functools import cache -from typing import Tuple # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -48,7 +47,7 @@ @cache # pragma: no cover -def HEXAMAPVTK(order: int) -> Tuple[npt.NDArray, npt.NDArray]: # pragma: no cover +def HEXAMAPVTK(order: int) -> tuple[npt.NDArray, npt.NDArray]: # pragma: no cover """ VTK -> IJK ordering for high-order hexahedrons > Loosely based on [Gmsh] "generatePointsHexCGNS" > [Jens Ulrich Kreber] "paraview-scripts/node_ordering. py" diff --git a/pyhope/mesh/connect/connect_rbtree.py b/pyhope/mesh/connect/connect_rbtree.py index 285964b8..b48fcfaf 100644 --- a/pyhope/mesh/connect/connect_rbtree.py +++ b/pyhope/mesh/connect/connect_rbtree.py @@ -28,7 +28,7 @@ from __future__ import annotations import bisect from dataclasses import dataclass -from typing import Optional, List, Tuple, cast +from typing import Optional, cast from typing import final from functools import cache, lru_cache # ---------------------------------------------------------------------------------------------------------------------------------- @@ -62,7 +62,7 @@ class LinkOffsetManager: def __init__(self) -> None: # Single breakpoint at stored_index=0 => offset=0 - self.breakpoints: List[Tuple[int, int]] = [(0, 0)] + self.breakpoints: list[tuple[int, int]] = [(0, 0)] def update(self, effective_index: int, @@ -362,7 +362,7 @@ def update(self, index: int, new_value: SIDE) -> None: node = self.node_at(index) node.value = new_value - def inorder(self, t: Optional[_RBTreeNode], result: List[SideNode]) -> None: + def inorder(self, t: Optional[_RBTreeNode], result: list[SideNode]) -> None: """ Recursively traverse the red-black tree in order and append node data to the result list """ if t is None: @@ -371,10 +371,10 @@ def inorder(self, t: Optional[_RBTreeNode], result: List[SideNode]) -> None: result.append(t.data) self.inorder( t.right, result) - def _to_list(self) -> List[SideNode]: + def _to_list(self) -> list[SideNode]: """ Return a Python list of the nodes (in order) via an in-order traversal of the red-black tree """ - result: List[SideNode] = [] + result: list[SideNode] = [] self.inorder(self._root, result) return result @@ -412,7 +412,7 @@ def _build_tree(nodes: tuple[_RBTreeNode, ...], start: int, end: int) -> Optiona return root @classmethod - def from_list(cls, sides: List[SIDE], offset_manager: LinkOffsetManager) -> RedBlackTree: + def from_list(cls, sides: list[SIDE], offset_manager: LinkOffsetManager) -> RedBlackTree: """ Optimized bulk conversion from a sorted list to a red–black tree > Assumes that the provided list is already in the desired in-order sequence > All nodes are initialized as black to maintain red–black properties @@ -455,7 +455,7 @@ def from_list(cls, sides: List[SIDE], offset_manager: LinkOffsetManager) -> RedB # node.value.sideID = idx # return [node.value for node in nodes] - def to_list(self) -> List[SIDE]: + def to_list(self) -> list[SIDE]: """ Convert the red-black tree back into a list of SIDE objects > Instead of computing each node's effective link individually (using a binary search for each call), we batch-process diff --git a/pyhope/mesh/elements/elements_ordering.py b/pyhope/mesh/elements/elements_ordering.py index c8c41e12..a312bd48 100644 --- a/pyhope/mesh/elements/elements_ordering.py +++ b/pyhope/mesh/elements/elements_ordering.py @@ -26,7 +26,6 @@ # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- from dataclasses import dataclass, field -from typing import Dict, List, Tuple # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -48,7 +47,7 @@ class ElementInfo: # Dictionary of dictionaries for face data, keyed by element type. # Each entry is a dictionary of face-name to node indices. - _faces_map: Dict[str, Dict[str, List[int]]] = field( + _faces_map: dict[str, dict[str, list[int]]] = field( default_factory=lambda: { 'pyramid13': { 'z-': [ 0, 1, 2, 3, 5, 6, 7, 8], 'y-': [ 0, 1, 4, 5, 10, 9], 'y+': [ 2, 3, 4, 7, 12, 11], @@ -77,7 +76,7 @@ class ElementInfo: } }) - _params_map: Dict[str, Dict[str, Tuple[float, float, float]]] = field( + _params_map: dict[str, dict[str, tuple[float, float, float]]] = field( default_factory=lambda: { 'hexahedron20': { 'z-': ( 0., 0., -1.), 'y-': ( 0., -1., 0.), 'x-': (-1., 0., 0.), @@ -94,7 +93,7 @@ class ElementInfo: } }) - def faces_to_nodes(self, elemType: str) -> Dict[str, List[int]]: + def faces_to_nodes(self, elemType: str) -> dict[str, list[int]]: """ Retrieves the face definitions for the specified element type. @@ -106,7 +105,7 @@ def faces_to_nodes(self, elemType: str) -> Dict[str, List[int]]: return self._faces_map[elemType] - def faces_to_params(self, elemType: str) -> Dict[str, Tuple[float, float, float]]: + def faces_to_params(self, elemType: str) -> dict[str, tuple[float, float, float]]: """ Retrieves the face parameters for the specified element type. diff --git a/pyhope/mesh/elements/elements_shapefunctions.py b/pyhope/mesh/elements/elements_shapefunctions.py index c28b6a12..88ac2405 100644 --- a/pyhope/mesh/elements/elements_shapefunctions.py +++ b/pyhope/mesh/elements/elements_shapefunctions.py @@ -27,7 +27,7 @@ # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations from dataclasses import dataclass, field -from typing import Callable, Dict, List +from typing import Callable # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -56,7 +56,7 @@ class ShapeFunctions: to a list of lambda functions. These functions compute the shape-function value at a given parametric coordinate (xi, eta, zeta) for the corresponding node. """ - shape_functions: Dict[str, List[Callable[[float, float, float], float]]] = field( + shape_functions: dict[str, list[Callable[[float, float, float], float]]] = field( default_factory=lambda: { # 20-Node Hexahedron (Hexa20) 'hexahedron20': [ diff --git a/pyhope/mesh/fem/fem.py b/pyhope/mesh/fem/fem.py index 95c2a33e..8d476f8d 100644 --- a/pyhope/mesh/fem/fem.py +++ b/pyhope/mesh/fem/fem.py @@ -27,7 +27,7 @@ # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations from collections import defaultdict -from typing import Dict, Tuple, cast +from typing import cast # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -290,7 +290,7 @@ def FEMConnect() -> None: # Build the vertex connectivity for elemID, elem in enumerate(elems): elemNodes = cast(np.ndarray, elem.nodes)[:cast(int, elem.type) % 10] - vertexInfo: Dict[int, Tuple[int, Tuple[int, ...]]] = {} + vertexInfo: dict[int, tuple[int, tuple[int, ...]]] = {} for locNode in range(len(elemNodes)): # Determine canonical vertex id node = int(elemNodes[locNode]) diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index de650071..af876877 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -27,7 +27,7 @@ # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations from functools import cache -from typing import Any, Final, Optional, Union, Tuple +from typing import Any, Final, Optional, Union # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -576,7 +576,7 @@ def face_to_nodes(face: str, elemType: int, nGeo: int, dtype=np.int32) -> npt.ND @cache -def dir_to_nodes(dir: str, elemType: Union[str, int], nGeo: int) -> Tuple[Any, bool]: +def dir_to_nodes(dir: str, elemType: Union[str, int], nGeo: int) -> tuple[Any, bool]: """ Returns the tensor-product nodes associated with a face """ if isinstance(elemType, str): diff --git a/pyhope/mesh/mesh_duplicates.py b/pyhope/mesh/mesh_duplicates.py index 6344d9f1..b5cdcac2 100644 --- a/pyhope/mesh/mesh_duplicates.py +++ b/pyhope/mesh/mesh_duplicates.py @@ -28,7 +28,7 @@ from __future__ import annotations import gc from collections import defaultdict -from typing import Dict, Final, Tuple, cast +from typing import Final, cast # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -177,16 +177,16 @@ def EliminateDuplicates() -> None: cdict: Final[dict] = mesh.cells_dict # Find the mapping to the (N-1)-dim elements - csetMap: Dict = { key: tuple(i for i, cell in enumerate(cset) if cell is not None and cast(np.ndarray, cell).size > 0) + csetMap: dict = { key: tuple(i for i, cell in enumerate(cset) if cell is not None and cast(np.ndarray, cell).size > 0) for key, cset in csets.items()} # Create new periodic nodes per (original node, boundary) pair # > Use a dictionary mapping (node, bc_key) --> new node index - nodeTrans: Dict[Tuple[int, str], int] = {} + nodeTrans: dict[tuple[int, str], int] = {} # > Collect points to append to the mesh newPoints: list = [] nPoints: Final[int] = points.shape[0] - BCNodes: Dict = {} + BCNodes: dict = {} for bc_key, cset in csets.items(): # Find the matching boundary condition diff --git a/pyhope/mesh/mesh_sort.py b/pyhope/mesh/mesh_sort.py index 6d30b5c0..5ab4e182 100644 --- a/pyhope/mesh/mesh_sort.py +++ b/pyhope/mesh/mesh_sort.py @@ -26,7 +26,7 @@ # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- import gc -from typing import Final, List, Optional, Tuple, cast, final +from typing import Final, Optional, cast, final # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -71,7 +71,7 @@ def UpdateElemID(elems : list, sorted_indices: npt.NDArray, bar, nElemsIJK : Optional[npt.NDArray] = None, - ) -> Tuple[List, List]: + ) -> tuple[list, list]: totalElems = len(elems) totalSides = len(sides) diff --git a/pyhope/mesh/mesh_vars.py b/pyhope/mesh/mesh_vars.py index 934e4204..e39e3c2f 100644 --- a/pyhope/mesh/mesh_vars.py +++ b/pyhope/mesh/mesh_vars.py @@ -30,7 +30,7 @@ from dataclasses import dataclass from enum import Enum, unique from functools import cache -from typing import Dict, Final, Optional, Union, Tuple, final +from typing import Final, Optional, Union, final # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -214,16 +214,16 @@ class ELEM: # Jacobian jacobian : Optional[float] = None # FEM connectivity - edgeInfo : Optional[Dict[int, # locEdgeIdx - Tuple[int, # locEdge + edgeInfo : Optional[dict[int, # locEdgeIdx + tuple[int, # locEdge int | None, # globalEdge - Tuple[int, ...], # FEMVertexID - Tuple[int, ...] # NodeID + tuple[int, ...], # FEMVertexID + tuple[int, ...] # NodeID ] ]] = None - vertexInfo : Optional[Dict[int, # locNodeIdx - Tuple[int, # FEMVertexID - Tuple[int, ...] # Vertex connectivity + vertexInfo : Optional[dict[int, # locNodeIdx + tuple[int, # FEMVertexID + tuple[int, ...] # Vertex connectivity ] ]] = None diff --git a/pyhope/mesh/sort/sort_hilbert.py b/pyhope/mesh/sort/sort_hilbert.py index 9a6367b2..79bc6c04 100644 --- a/pyhope/mesh/sort/sort_hilbert.py +++ b/pyhope/mesh/sort/sort_hilbert.py @@ -26,7 +26,7 @@ # ---------------------------------------------------------------------------------------------------------------------------------- # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- -from typing import List, Literal, Iterable, Union, overload +from typing import Literal, Iterable, Union, overload # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -64,14 +64,14 @@ def HilbertCurveNumpy() -> None: # Typing helpers @overload - def _distances_from_points_numpy(self, points: npt.NDArray, match_type: Literal[False] = False) -> List: ... + def _distances_from_points_numpy(self, points: npt.NDArray, match_type: Literal[False] = False) -> list: ... @overload - def _distances_from_points_numpy(self, points: List , match_type: Literal[True]) -> List: ... + def _distances_from_points_numpy(self, points: list , match_type: Literal[True]) -> list: ... @overload def _distances_from_points_numpy(self, points: npt.NDArray, match_type: Literal[True]) -> npt.NDArray: ... # Function def _distances_from_points_numpy(self, - points : Union[List, npt.NDArray], + points : Union[list, npt.NDArray], match_type: bool = False) -> Union[npt.NDArray, list]: """ Batch implementation for distances_from_points in numpy """ diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 00aa562a..73cfbe92 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -29,7 +29,7 @@ import gc from collections import defaultdict from functools import cache -from typing import Final, Tuple, cast +from typing import Final, cast # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -372,7 +372,7 @@ def tet_to_hex_points(order: int, z_split: bool = False) -> tuple[npt.NDArray, . @cache -def tet_to_hex_faces(z_split: bool = False) -> Tuple[list[npt.NDArray], list[list[npt.NDArray]]]: +def tet_to_hex_faces(z_split: bool = False) -> tuple[list[npt.NDArray], list[list[npt.NDArray]]]: """ Given the 4 corner node indices of a single tetrahedral element (indexed 0..3), return the 4 triangular faces and the 12 quadrilateral faces """ @@ -465,7 +465,7 @@ def prism_to_hex_points(order: int, z_split: bool = False) -> tuple[npt.NDArray, @cache -def prism_to_hex_faces(z_split: bool = False) -> Tuple[list[npt.NDArray], list[list[npt.NDArray]]]: +def prism_to_hex_faces(z_split: bool = False) -> tuple[list[npt.NDArray], list[list[npt.NDArray]]]: """ Given the 6 corner node indices of a single prism element (indexed 0..5), return the original faces and the corresponding new quadrilateral sub-faces. """ @@ -589,7 +589,7 @@ def hex_to_hex_points(order: int, z_split: bool = False) -> tuple[npt.NDArray, . @cache -def hex_to_hex_faces(z_split: bool = False) -> Tuple[list[npt.NDArray], list[list[npt.NDArray]]]: +def hex_to_hex_faces(z_split: bool = False) -> tuple[list[npt.NDArray], list[list[npt.NDArray]]]: """ Given the 8 corner node indices of a single hexahedron element (indexed 0..7), return the 6 quadrilateral faces and the 24 quadrilateral faces after splitting """ diff --git a/pyhope/meshio/meshio_convert.py b/pyhope/meshio/meshio_convert.py index 546b5439..0b74cde3 100644 --- a/pyhope/meshio/meshio_convert.py +++ b/pyhope/meshio/meshio_convert.py @@ -28,7 +28,7 @@ # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations import importlib -from typing import Dict, Final, List, Set, cast +from typing import Final, cast # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -128,18 +128,18 @@ def meshio_to_gmsh(mesh: meshio.Mesh) -> meshio.Mesh: surface_cells = [cell_block for cell_block in mesh.cells if cell_block.type in gmshCellTypes.cellTypes2D] # Build new arrays - celll: List[meshio.CellBlock] = [] - celldphys: List[npt.NDArray ] = [] - celldgeom: List[npt.NDArray ] = [] + celll: list[meshio.CellBlock] = [] + celldphys: list[npt.NDArray ] = [] + celldgeom: list[npt.NDArray ] = [] # Unique geometrical entity ids per dimension # > 0: 3D entities, 1: 2D entities geom_id: npt.NDArray = np.ones((2,), dtype=int) - geom_tag: List[List[int]] = [[] for _ in range(2)] - geom_nodes: List[List[int]] = [[] for _ in range(2)] + geom_tag: list[list[int]] = [[] for _ in range(2)] + geom_nodes: list[list[int]] = [[] for _ in range(2)] # Set to keep track of nodes already used to represent an entity in gmsh:dim_tags - usedNodes: Set[int] = set() + usedNodes: set[int] = set() # Process each 3D CellBlock: keep shared connectivity, set tags # WARNING: Each 3D CellBlock neets to get its OWN geometrical tag so that @@ -263,7 +263,7 @@ def meshio_to_gmsh(mesh: meshio.Mesh) -> meshio.Mesh: gmshMesh.point_data.update({'gmsh:dim_tags': dim_tags}) # Add PhysicalNames so groups are not missing in the Gmsh output - field_data: Dict[str, npt.NDArray] = {} + field_data: dict[str, npt.NDArray] = {} # Add volume physical group (3D) if len(geom_tag[0]) > 0: diff --git a/pyhope/meshio/meshio_nodes.py b/pyhope/meshio/meshio_nodes.py index 1d7c1f82..c9d680be 100644 --- a/pyhope/meshio/meshio_nodes.py +++ b/pyhope/meshio/meshio_nodes.py @@ -26,7 +26,6 @@ # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- from dataclasses import dataclass, field -from typing import Dict # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -43,7 +42,7 @@ # See for the node ordering. @dataclass(repr=False, eq=False, slots=True, frozen=True) class NumNodesPerCell: - _data: Dict[str, int] = field(init=False, repr=False) + _data: dict[str, int] = field(init=False, repr=False) def __post_init__(self): object.__setattr__(self, '_data', { diff --git a/pyhope/meshio/meshio_ordering.py b/pyhope/meshio/meshio_ordering.py index c5bf984d..2a1c8a2c 100644 --- a/pyhope/meshio/meshio_ordering.py +++ b/pyhope/meshio/meshio_ordering.py @@ -29,7 +29,7 @@ from __future__ import annotations from dataclasses import dataclass, field from functools import cache -from typing import Dict, List, Union, Optional +from typing import Union, Optional # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -60,7 +60,7 @@ def HEXREORDER(order: int, incomplete: Optional[bool] = False) -> tuple[int]: order += 1 nNodes = 8 + 12*(order - 2) if incomplete else order**3 - map: List = [None for _ in range(nNodes)] + map: list = [None for _ in range(nNodes)] count = 0 # Recursively build the mapping @@ -180,7 +180,7 @@ class NodeOrdering: """ # Dictionary for translation of meshio types to gmsh codes # http://gmsh.info//doc/texinfo/gmsh.html#MSH-file-format-version-2 - _gmsh_typing: Dict[int, str] = field( + _gmsh_typing: dict[int, str] = field( default_factory=lambda: { 1 : 'line' , 2 : 'triangle' , 3 : 'quad' , 4 : 'tetra' , 5 : 'hexahedron' , 6 : 'wedge' , 7 : 'pyramid' , 8 : 'line3' , 9 : 'triangle6' , 10 : 'quad9' , 11 : 'tetra10' , 12 : 'hexahedron27' , @@ -203,7 +203,7 @@ class NodeOrdering: # Dictionary for conversion Gmsh to meshIO # > TODO: IMPLEMENT RECURSIVE MAPPING USING IO_MESHIO/IO_GMSH - _meshio_ordering: Dict[str, List[int]] = field( + _meshio_ordering: dict[str, list[int]] = field( default_factory=lambda: { # 0D elements # > Vertex # 'vertex' : [ 0 ], @@ -247,14 +247,14 @@ class NodeOrdering: # ) # Dictionary for translation of gambit types to gmsh codes - _gambit_typing: Dict[int, str] = field( + _gambit_typing: dict[int, str] = field( default_factory=lambda: { 1 : 'line' , 2 : 'quad' , 3 : 'triangle' , 4 : 'hexahedron' , 5 : 'wedge' , 6 : 'tetrahedron' , 7 : 'pyramid' , } ) # Dictionary for conversion of Gambit to meshIO - _gambit_ordering: Dict[str, List[int]] = field( + _gambit_ordering: dict[str, list[int]] = field( default_factory=lambda: { # 0D elements # 1D elements # 2D elements From d011766e1080f3557ff6116f43e78880d3b7cc88 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:45:00 +0100 Subject: [PATCH 09/59] Linting: Fix try-consider-else (TRY300) --- pyhope/gmsh/gmsh_install.py | 4 ++-- pyhope/readintools/readintools.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pyhope/gmsh/gmsh_install.py b/pyhope/gmsh/gmsh_install.py index e85f7ed5..cb99eb31 100644 --- a/pyhope/gmsh/gmsh_install.py +++ b/pyhope/gmsh/gmsh_install.py @@ -50,10 +50,10 @@ def PkgsMetaData(pkgs, classifier) -> Optional[bool]: try: meta = metadata.metadata(pkgs) classifiers = meta.get_all('Classifier', []) - return classifier in classifiers - except metadata.PackageNotFoundError: return None + else: + return classifier in classifiers def PkgsMetaVersion(pkgs) -> Optional[str]: diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index aadd2cec..0023d77b 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -115,9 +115,10 @@ def is_numeric(var_value: str) -> bool: """ try: float(var_value) - return True except ValueError: return False + else: + return True # ================================================================================================================================== From 90d69964c4bccc3b46422f5f80f2b8cb2cfdd29b Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:45:43 +0100 Subject: [PATCH 10/59] Linting: Fix set-attr-with-constant (B010) --- pyhope/meshio/meshio_convert.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhope/meshio/meshio_convert.py b/pyhope/meshio/meshio_convert.py index 0b74cde3..39ba89ff 100644 --- a/pyhope/meshio/meshio_convert.py +++ b/pyhope/meshio/meshio_convert.py @@ -307,7 +307,7 @@ def MeshioGmshOrderingPatch() -> None: for mod_name in ('meshio.gmsh._gmsh', 'meshio.gmsh._gmsh41', 'meshio.gmsh._gmsh22', 'meshio.gmsh._gmsh4'): try: mod = importlib.import_module(mod_name) - setattr(mod, '_meshio_to_gmsh_order', NodeOrdering().ordering_meshio_to_gmsh) + mod._meshio_to_gmsh_order = NodeOrdering().ordering_meshio_to_gmsh except Exception: # If assignment fails, pass pass From 5be81a9d0ad98aabac7d8d140af8d6f8c15d6297 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:47:58 +0100 Subject: [PATCH 11/59] Linting: Fix loop-variable-overrides-iterator (B020) --- pyhope/meshio/meshio_convert.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyhope/meshio/meshio_convert.py b/pyhope/meshio/meshio_convert.py index 39ba89ff..71ec6d37 100644 --- a/pyhope/meshio/meshio_convert.py +++ b/pyhope/meshio/meshio_convert.py @@ -71,16 +71,16 @@ def gmsh_to_meshio(gmsh) -> meshio.Mesh: # Extract cells elem_types, elem_tags, node_tags = gmsh.model.mesh.getElements() cells = [] - for elem_type, elem_tags, node_tags in zip(elem_types, elem_tags, node_tags): + for elemType, elemTags, nodeTags in zip(elem_types, elem_tags, node_tags): # `elementName', `dim', `order', `numNodes', `localNodeCoord', `numPrimaryNodes' - num_nodes_per_cell = gmsh.model.mesh.getElementProperties(elem_type)[3] + num_nodes_per_cell = gmsh.model.mesh.getElementProperties(elemType)[3] - node_tags_reshaped = np.asarray(node_tags).reshape(-1, num_nodes_per_cell) - 1 - node_tags_reshaped = node_ordering.ordering_gmsh_to_meshio(elem_type, node_tags_reshaped) + node_tags_reshaped = np.asarray(nodeTags).reshape(-1, num_nodes_per_cell) - 1 + node_tags_reshaped = node_ordering.ordering_gmsh_to_meshio(elemType, node_tags_reshaped) # NRG: Fix the element ordering - node_tags_sorted = node_tags_reshaped[np.argsort(elem_tags)] - cells.append(meshio.CellBlock(meshio.gmsh.gmsh_to_meshio_type[elem_type], node_tags_sorted)) + node_tags_sorted = node_tags_reshaped[np.argsort(elemTags)] + cells.append(meshio.CellBlock(meshio.gmsh.gmsh_to_meshio_type[elemType], node_tags_sorted)) cell_sets = {} for dim, tag in gmsh.model.getPhysicalGroups(): From 1f15f90764295a7324a3822dec45428ddd56fb0c Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:52:43 +0100 Subject: [PATCH 12/59] Linting: Ignore dict-index-missing-items (PLC0206) --- pyhope/mesh/extrude/mesh_extrude.py | 4 ++-- pyhope/mesh/topology/mesh_splittohex.py | 4 ++-- pyhope/mesh/topology/mesh_topology.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index 94e0b048..4b5f7bd0 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -280,7 +280,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: elems_new = {} csets_new = {} - for key in elems_lst: + for key in elems_lst: # noqa: PLC0206 if isinstance(elems_lst[key], list) and elems_lst[key]: # noqa: E271 # Convert the list of accumulated arrays/lists into a single NumPy array elems_new[key] = np.array(elems_lst[key], dtype=int) @@ -288,7 +288,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: # Determine the expected number of columns elems_new[key] = np.empty((0, faceNum[faceType.index(key)]), dtype=int) - for key in csets_lst: + for key in csets_lst: # noqa: PLC0206 csets_new[key] = tuple(np.array(lst, dtype=int) for lst in csets_lst[key]) # Convert points_list back to a NumPy array diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 73cfbe92..4ef5048a 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -305,7 +305,7 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: elems_new = {} csets_new = {} - for key in elems_lst: + for key in elems_lst: # noqa: PLC0206 if isinstance(elems_lst[key], list) and elems_lst[key]: # noqa: E271 # Convert the list of accumulated arrays/lists into a single NumPy array elems_new[key] = np.array(elems_lst[key], dtype=int) @@ -313,7 +313,7 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: # Determine the expected number of columns elems_new[key] = np.empty((0, faceNum[faceType.index(key)]), dtype=int) - for key in csets_lst: + for key in csets_lst: # noqa: PLC0206 csets_new[key] = tuple(np.array(lst, dtype=int) for lst in csets_lst[key]) # Convert points_list back to a NumPy array diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 9768366f..cc0dd55c 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -279,7 +279,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: elems_new = {} csets_new = {} - for key in elems_lst: + for key in elems_lst: # noqa: PLC0206 if isinstance(elems_lst[key], list) and elems_lst[key]: # noqa: E271 # Convert the list of accumulated arrays/lists into a single NumPy array elems_new[key] = np.array(elems_lst[key], dtype=int) @@ -287,7 +287,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: # Determine the expected number of columns elems_new[key] = np.empty((0, faceNum[faceType.index(key)]), dtype=int) - for key in csets_lst: + for key in csets_lst: # noqa: PLC0206 csets_new[key] = tuple(np.array(lst, dtype=int) for lst in csets_lst[key]) # Convert points_list back to a NumPy array From 6773d601abf1ee06b393af154b89669484693eaf Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:54:44 +0100 Subject: [PATCH 13/59] Linting: Ignore unnecessary-iterable-allocation-for-first-element (RUF015) --- pyhope/mesh/reader/reader_gmsh.py | 8 ++++---- pyhope/mesh/topology/mesh_topology.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 77cfaec3..88957823 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -304,8 +304,8 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: stree = None if any('quad' in key for key in mesh.cells_dict): - nConnSide = [value for key, value in mesh.cells_dict.items() if 'quad' in key][0] - nConnType = [key for key, _ in mesh.cells_dict.items() if 'quad' in key][0] # noqa: E272, E501 + nConnSide = next(value for key, value in mesh.cells_dict.items() if 'quad' in key) + nConnType = next(key for key, _ in mesh.cells_dict.items() if 'quad' in key) # noqa: E272, E501 nConnNum = cells_lst.index(nConnType) nConnLen = len(cells_lst) @@ -325,8 +325,8 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: ttree = None if any('triangle' in key for key in mesh.cells_dict): - tConnSide = [value for key, value in mesh.cells_dict.items() if 'triangle' in key][0] - tConnType = [key for key, _ in mesh.cells_dict.items() if 'triangle' in key][0] # FIXME: Support mixed LO/HO meshes # noqa: E272, E501 + tConnSide = next(value for key, value in mesh.cells_dict.items() if 'triangle' in key) + tConnType = next(key for key, _ in mesh.cells_dict.items() if 'triangle' in key) # FIXME: Support mixed LO/HO meshes # noqa: E272, E501 tConnNum = cells_lst.index(tConnType) tConnLen = len(cells_lst) diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index cc0dd55c..90dae2ce 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -179,7 +179,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: for iElem, meshcell in enumerate(meshcells): _ , mdict = meshcell - mtype, mcell = list(cast(dict, mdict).keys())[0], list(cast(dict, mdict).values())[0] + mtype, mcell = next(iter(cast(dict, mdict).keys())), next(iter(cast(dict, mdict).values())) elemType = elemTypes[iElem] elemName = elemNames[iElem] From f4d73cdb9597211e566335fd86c824580dd1c574 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 14:57:24 +0100 Subject: [PATCH 14/59] Linting: Fix incorrect-dict-iterator (PERF102) --- pyhope/mesh/connect/connect_mortar.py | 2 +- pyhope/mesh/extrude/mesh_extrude.py | 2 +- pyhope/mesh/reader/reader_gmsh.py | 4 ++-- pyhope/mesh/topology/mesh_topology.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index 5f442c83..51b19178 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -657,7 +657,7 @@ def find_edge_combinations(comboEdges) -> tuple: validCombo = [] # Iterate over all points and their associated edges - for _, edges in pointToEdges.items(): + for edges in pointToEdges.values(): if len(edges) < 2: # Skip points with less than 2 edges continue diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index 4b5f7bd0..f09c0a6c 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -163,7 +163,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: case _: hopout.error('Found more than one boundary condition for extrusion, exiting...') - nTotalElems = sum(cdata.shape[0] for _, zdata in meshcells for _, cdata in cast(dict, zdata).items()) + nTotalElems = sum(cdata.shape[0] for _, zdata in meshcells for cdata in cast(dict, zdata).values()) bar = ProgressBar(value=nTotalElems, title='│ Processing Elements', length=33, threshold=1000) # Build an inverted index to map each node to all face keys (from csets_old) that contain it diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 88957823..ccd169d4 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -305,7 +305,7 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: if any('quad' in key for key in mesh.cells_dict): nConnSide = next(value for key, value in mesh.cells_dict.items() if 'quad' in key) - nConnType = next(key for key, _ in mesh.cells_dict.items() if 'quad' in key) # noqa: E272, E501 + nConnType = next(key for key in mesh.cells_dict if 'quad' in key) # noqa: E272, E501 nConnNum = cells_lst.index(nConnType) nConnLen = len(cells_lst) @@ -326,7 +326,7 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: if any('triangle' in key for key in mesh.cells_dict): tConnSide = next(value for key, value in mesh.cells_dict.items() if 'triangle' in key) - tConnType = next(key for key, _ in mesh.cells_dict.items() if 'triangle' in key) # FIXME: Support mixed LO/HO meshes # noqa: E272, E501 + tConnType = next(key for key in mesh.cells_dict if 'triangle' in key) # FIXME: Support mixed LO/HO meshes # noqa: E272, E501 tConnNum = cells_lst.index(tConnType) tConnLen = len(cells_lst) diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 90dae2ce..8873c652 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -168,7 +168,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: meshcells = tuple(('Zone1', {k: np.array([i for i in range(len(v))])}) for k, v in mesh.cells_dict.items() if k.startswith('hexahedron')) - nTotalElems = sum(cdata.shape[0] for _, zdata in meshcells for _, cdata in cast(dict, zdata).items()) + nTotalElems = sum(cdata.shape[0] for _, zdata in meshcells for cdata in cast(dict, zdata).values()) bar = ProgressBar(value=nTotalElems, title='│ Processing Elements', length=33, threshold=1000) # Build an inverted index to map each node to all face keys (from csets_old) that contain it From f26b090faccd83c014e5aa47dc14ec5c60b747a9 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:00:01 +0100 Subject: [PATCH 15/59] Linting: Fix deprecated-import (UP035) --- pyhope/common/common_parallel.py | 3 ++- pyhope/common/common_vars.py | 3 ++- pyhope/mesh/elements/elements_shapefunctions.py | 2 +- pyhope/mesh/sort/sort_hilbert.py | 3 ++- pyhope/mesh/topology/mesh_topology.py | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/pyhope/common/common_parallel.py b/pyhope/common/common_parallel.py index dec0e44a..806ccdb9 100644 --- a/pyhope/common/common_parallel.py +++ b/pyhope/common/common_parallel.py @@ -27,8 +27,9 @@ # ---------------------------------------------------------------------------------------------------------------------------------- import sys import traceback +from collections.abc import Callable from multiprocessing import Pool, Queue, Process -from typing import Callable, Union +from typing import Union # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/pyhope/common/common_vars.py b/pyhope/common/common_vars.py index 570da32b..ca994032 100644 --- a/pyhope/common/common_vars.py +++ b/pyhope/common/common_vars.py @@ -30,9 +30,10 @@ import pathlib import re import subprocess +from collections.abc import Callable from enum import Enum, unique from functools import cache -from typing import Callable, Final, Optional, final +from typing import Final, Optional, final from typing_extensions import Self # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries diff --git a/pyhope/mesh/elements/elements_shapefunctions.py b/pyhope/mesh/elements/elements_shapefunctions.py index 88ac2405..65d9007c 100644 --- a/pyhope/mesh/elements/elements_shapefunctions.py +++ b/pyhope/mesh/elements/elements_shapefunctions.py @@ -26,8 +26,8 @@ # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations +from collections.abc import Callable from dataclasses import dataclass, field -from typing import Callable # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/pyhope/mesh/sort/sort_hilbert.py b/pyhope/mesh/sort/sort_hilbert.py index 79bc6c04..5c97652c 100644 --- a/pyhope/mesh/sort/sort_hilbert.py +++ b/pyhope/mesh/sort/sort_hilbert.py @@ -26,7 +26,8 @@ # ---------------------------------------------------------------------------------------------------------------------------------- # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- -from typing import Literal, Iterable, Union, overload +from collections.abc import Iterable +from typing import Literal, Union, overload # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 8873c652..1126cfd2 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -28,8 +28,9 @@ from __future__ import annotations import gc from collections import defaultdict +from collections.abc import Callable from functools import cache -from typing import Callable, Optional, Union +from typing import Optional, Union from typing import cast # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries From 058c50a6653c365f32a24371c5430925494a05a3 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:00:56 +0100 Subject: [PATCH 16/59] Linting: Fix manual-list-comprehension (PERF401) --- pyhope/common/common_template.py | 5 +---- pyhope/mesh/fem/fem.py | 4 +--- pyhope/mesh/mesh_common.py | 3 +-- pyhope/mesh/topology/mesh_splittohex.py | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/pyhope/common/common_template.py b/pyhope/common/common_template.py index 79140b28..69660b08 100644 --- a/pyhope/common/common_template.py +++ b/pyhope/common/common_template.py @@ -83,9 +83,6 @@ def LoadTemplate(template: str, if templateModule is None: hopout.warning(f'{reason} template "{template}" not found!') # Print all available default templates for post-deformation - templist = [] - for file in os.listdir(os.path.join(os.path.dirname(origin), 'templates')): - if file.endswith('.py'): - templist.append(f' {file[:-3]}') + templist = [f' {file[:-3]}' for file in os.listdir(os.path.join(os.path.dirname(origin), 'templates')) if file.endswith('.py')] hopout.error('Available default extrusion templates:' + ','.join(templist)) return templateModule diff --git a/pyhope/mesh/fem/fem.py b/pyhope/mesh/fem/fem.py index 8d476f8d..539ba61b 100644 --- a/pyhope/mesh/fem/fem.py +++ b/pyhope/mesh/fem/fem.py @@ -104,9 +104,7 @@ def FEMConnect() -> None: continue component.add(currentNode) - for nxt in periGraph[currentNode]: - if nxt not in component: - stack.append(nxt) + stack.extend(nxt for nxt in periGraph[currentNode] if nxt not in component) canonical_rep = min(component) for v in component: diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index af876877..fa641d67 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -348,8 +348,7 @@ def FaceOrdering(side_type: str, order: int, dtype=np.int32) -> npt.NDArray: # Build the tensor ordering as a list of (i, j) for which i+j <= p. nodes = [] for i in range(p+1): - for j in range(p+1 - i): - nodes.append((i, j)) + nodes.extend((i, j) for j in range(p+1 - i)) # Define vertices in the reference triangle: vertices = [(0, 0), (p, 0), (0, p)] # Edge from vertex0 (0,0) to vertex1 (p,0): nodes with j==0 (excluding vertices) diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 4ef5048a..f2f07d4f 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -247,8 +247,7 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: # Create the new quadrilateral boundary faces by precomputing the frozensets faceSet = [frozenset(face) for face in subFaces] # This cannot be a tuple, we need to iterate over all the candidate sets - for key in faceSet: - newBCFaces.append((key, combined_name)) + newBCFaces.extend((key, combined_name) for key in faceSet) # Done with this triangular face, break out of the (inner) candidate loop break From 9c85239bd820f23b5dc23059f618cccc5f1b7e1e Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:03:08 +0100 Subject: [PATCH 17/59] Linting: Fix collapsible-if (SIM102) --- pyhope/mesh/mesh_external.py | 8 ++--- pyhope/mesh/reader/reader_gambit.py | 15 ++++----- pyhope/mesh/topology/mesh_splittohex.py | 43 ++++++++++++------------- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/pyhope/mesh/mesh_external.py b/pyhope/mesh/mesh_external.py index f6c383a3..bc75f4e7 100644 --- a/pyhope/mesh/mesh_external.py +++ b/pyhope/mesh/mesh_external.py @@ -98,10 +98,10 @@ def MeshExternal() -> meshio.Mesh: else: hopout.error(f'Mesh file [󰇘]/{os.path.basename(fname)} does not exist') - if not all(compatibleGMSH(fname) for fname in fnames): - if any(compatibleGMSH(fname) for fname in fnames): - hopout.warning('Mixed file formats detected, this is untested and may not work') - # sys.exit(1) + if not all(compatibleGMSH(fname) for fname in fnames) \ + and any(compatibleGMSH(fname) for fname in fnames): + hopout.warning('Mixed file formats detected, this is untested and may not work') + # sys.exit(1) # Check the file sizes fsizes = tuple(os.stat(f).st_size for f in fnames) diff --git a/pyhope/mesh/reader/reader_gambit.py b/pyhope/mesh/reader/reader_gambit.py index 65c9c08d..22384ffe 100644 --- a/pyhope/mesh/reader/reader_gambit.py +++ b/pyhope/mesh/reader/reader_gambit.py @@ -180,10 +180,9 @@ def ReadGambit(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: for line in grsIter: lnum += 1 # Iterate until the number of boundary conditions is reached - if 'ENDOFSECTION' in line: - # Check if the next sections is also an element group - if 'ELEMENT GROUP' not in content[grsLine+lnum]: - break + # > Check if the next sections is also an element group + if 'ENDOFSECTION' in line and 'ELEMENT GROUP' not in content[grsLine+lnum]: + break tokens = line.strip().split() if not tokens: @@ -228,10 +227,10 @@ def ReadGambit(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: for line in bcsIter: # Iterate until the number of boundary conditions is reached lnum += 1 - if 'ENDOFSECTION' in line: - # Check if the next sections is also a boundary condition - if bcsLine+lnum >= len(content) or 'BOUNDARY CONDITIONS' not in content[bcsLine+lnum]: - break + # Check if the next sections is also a boundary condition + if 'ENDOFSECTION' in line \ + and (bcsLine+lnum >= len(content) or 'BOUNDARY CONDITIONS' not in content[bcsLine+lnum]): + break tokens = line.strip().split() if not tokens: diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index f2f07d4f..99ebce4e 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -178,28 +178,27 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: for cell in elems_old: ctype, cdata = cell.type, cell.data - if ctype.startswith('hexahedron'): - # Carry over the original hexahedra volume cells unchanged - if not splitToHexZ: - elems_lst.setdefault('hexahedron', []).extend(cdata) - - # Detect which existing quad boundary faces are attached to these hexahedra - for elem in cdata: - for face in hexa_faces(): - fNodes = np.array(elem)[face] - fSet = frozenset(fNodes) - - candidate_sets = [nodeToFace[node] for node in fSet if node in nodeToFace] - if not candidate_sets: - continue - - common_candidates = set.intersection(*candidate_sets) - for candidate in common_candidates: - if fSet.issubset(candidate): - hexBCQuads.add(candidate) - - # Skip the rest of the hexahedrons - continue + # Carry over the original hexahedra volume cells unchanged + if ctype.startswith('hexahedron') and not splitToHexZ: + elems_lst.setdefault('hexahedron', []).extend(cdata) + + # Detect which existing quad boundary faces are attached to these hexahedra + for elem in cdata: + for face in hexa_faces(): + fNodes = np.array(elem)[face] + fSet = frozenset(fNodes) + + candidate_sets = [nodeToFace[node] for node in fSet if node in nodeToFace] + if not candidate_sets: + continue + + common_candidates = set.intersection(*candidate_sets) + for candidate in common_candidates: + if fSet.issubset(candidate): + hexBCQuads.add(candidate) + + # Skip the rest of the hexahedrons + continue splitPoints, splitElems, splitFaces = elemSplitter.get(ctype, (None, None, None)) From b492fd9a382f7a8179edbd3d7cadceff5121c75c Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:04:05 +0100 Subject: [PATCH 18/59] Linting: Fix comparison-of-constant (PLR0133) --- pyhope/mesh/topology/mesh_splittohex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 99ebce4e..af8ca649 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -72,8 +72,8 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: hopout.info('SPLITTING ELEMENTS TO HEXAHEDRA...') hopout.sep() - splitToHex = (GetLogical('doSplitToHex') if CountOption('doSplitToHex') else False > 0) or \ - (GetLogical( 'SplitToHex') if CountOption( 'SplitToHex') else False > 0) + splitToHex = (GetLogical('doSplitToHex') if CountOption('doSplitToHex') > 0 else False) or \ + (GetLogical( 'SplitToHex') if CountOption( 'SplitToHex') > 0 else False) if not splitToHex: hopout.separator() return mesh From 7b7e6681cf2172996ef2e0558c66a7482add5082 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:05:09 +0100 Subject: [PATCH 19/59] Linting: Fix unnecessary-literal-within-tuple-call (C409) --- pyhope/basis/basis_jacobian.py | 2 +- pyhope/mesh/mesh_common.py | 2 +- pyhope/mesh/reader/reader_hopr.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyhope/basis/basis_jacobian.py b/pyhope/basis/basis_jacobian.py index 96a44280..75912829 100644 --- a/pyhope/basis/basis_jacobian.py +++ b/pyhope/basis/basis_jacobian.py @@ -201,7 +201,7 @@ def CheckJacobians() -> None: # Pre-compute LINTEN mappings for all element types linCache = {} elemOrder = 100 if mesh_vars.nGeo == 1 else 200 - elemTypes = tuple([s + elemOrder for s in elemBases]) + elemTypes = tuple(s + elemOrder for s in elemBases) for elemType in elemTypes: try: _, mapLin = LINTEN(elemType, order=mesh_vars.nGeo) diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index fa641d67..9152f6c0 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -440,7 +440,7 @@ def sidetovol2(N: int, flip: int, face: str, elemType: Union[str, int], dtype=np # Vectorize flip_s2m to get the flipped (p, q) values vec_flip = (np.vectorize(lambda p, q: flip_s2m(N, p, q, flip, elemType)[0], otypes=[dtype]), np.vectorize(lambda p, q: flip_s2m(N, p, q, flip, elemType)[1], otypes=[dtype])) - pq = tuple([vec_flip[s](P, Q) for s in (0, 1)]) + pq = tuple(vec_flip[s](P, Q) for s in (0, 1)) # Vectorize the cgns_sidetovol function vec_cgns = np.vectorize(lambda r, p, q: cgns_sidetovol(N, r, int(p), int(q), face, elemType), otypes=[dtype], signature='(),(),()->(n)') diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index 8ea11334..e72fcb2d 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -163,7 +163,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: # > Cache the mapping here, so we consider the mesh order linCache = {} elemOrder = 100 if mesh_vars.nGeo == 1 else 200 - elemTypes = tuple([s + elemOrder for s in (4, 5, 6, 8)]) + elemTypes = tuple(s + elemOrder for s in (4, 5, 6, 8)) for elemType in elemTypes: try: _, mapLin = LINTEN(elemType, order=mesh_vars.nGeo) From 160889d03e689dd0d4183b1fd8e9f09db260fa2c Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:07:42 +0100 Subject: [PATCH 20/59] Linting: Fix format-literals (UP030) --- pyhope/mesh/mesh_external.py | 2 +- pyhope/mesh/reader/reader_hopr.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/mesh_external.py b/pyhope/mesh/mesh_external.py index bc75f4e7..9411ba24 100644 --- a/pyhope/mesh/mesh_external.py +++ b/pyhope/mesh/mesh_external.py @@ -151,7 +151,7 @@ def MeshExternal() -> meshio.Mesh: vvs = recontruct_periodicity(mesh) hopout.routine('The following vectors were recovered:') for iVV, vv in enumerate(vvs): - hopout.printoption(f'vv[{iVV+1}]', '{0:}'.format(np.round(vv['Dir'], 6)), 'RECOVER') + hopout.printoption(f'vv[{iVV+1}]', f'{np.round(vv["Dir"], 6)}', 'READ IN') hopout.sep() # Flag mortar rebuild if merging multiple meshes diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index e72fcb2d..bda78122 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -120,7 +120,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: hopout.sep() hopout.routine('The following vectors were found:') for iVV, vv in enumerate(mesh_vars.vvs): - hopout.printoption(f'vv[{iVV+1}]', '{0:}'.format(np.round(vv['Dir'], 6)), 'READ IN') + hopout.printoption(f'vv[{iVV+1}]', f'{np.round(vv["Dir"], 6)}', 'READ IN') hopout.sep() # old hopr files might not contain the VV except KeyError: From d5259487cd8a89867e0fad024a3410dd0166b408 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:08:59 +0100 Subject: [PATCH 21/59] Linting: Fix unnecessary-map (C417) --- pyhope/mesh/reader/reader_gmsh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index ccd169d4..1ea103fa 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -437,7 +437,7 @@ def BCCGNS_Unstructured( mesh: meshio.Mesh, cellsets = mesh.cell_sets # Convert the cellsets to a list of lists for easier manipulation for k, v in cellsets.items(): - cellsets[k] = list(map(lambda cell: cell.tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell, v)) + cellsets[k] = [cell.tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell for cell in v] for zoneBC in zoneBCs: # Lists to collect centroids @@ -638,7 +638,7 @@ def BCCGNS_Structured(mesh: meshio.Mesh, cellsets = mesh.cell_sets # Convert the cellsets to a list of lists for easier manipulation for k, v in cellsets.items(): - cellsets[k] = list(map(lambda cell: cell.tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell, v)) + cellsets[k] = [cell.tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell for cell in v] # Load the zone BCs for zoneBC, bcData in zone['ZoneBC'].items(): From 496b9b936cd74e6d1f2b3c7d4728b7434866730c Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:11:01 +0100 Subject: [PATCH 22/59] Linting: Fix unnecessary-generator-set (C401) --- pyhope/mesh/reader/reader_gmsh.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 1ea103fa..d71d7d34 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -492,7 +492,7 @@ def BCCGNS_Unstructured( mesh: meshio.Mesh, if cgnsGridLoc == 'Vertex': # Check if corners can form a subset of cgnsBC - corners_set = set(int(s) for s in corners) + corners_set = {int(s) for s in corners} if corners_set.issubset(cgns_set): BCpoints = bpoints[[s-1 for s in corners]] quadCenters.append(np.mean(BCpoints, axis=0)) From cbdfbeb7cae3a53ec08da8a649e7de61cc810c60 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:11:33 +0100 Subject: [PATCH 23/59] Linting: Fix unnecessary-literal-set (C405) --- pyhope/mesh/mesh_builtin.py | 2 +- pyhope/mesh/reader/reader_gmsh.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index 75753486..9b9a99ce 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -394,7 +394,7 @@ def MeshCartesian() -> meshio.Mesh: for elem in gmshIssue: print(hopout.warn(f'Wrong Gmsh order {elem[1]} for element {elem[0].replace(" ", "")}')) elemOrders = set([int(elem[1]) for elem in gmshIssue]) - hopout.error(f'Gmsh element order(s) {elemOrders} does not match requested mesh order {set([mesh_vars.nGeo])}') + hopout.error(f'Gmsh element order(s) {elemOrders} does not match requested mesh order { {mesh_vars.nGeo} }') # Convert Gmsh object to meshio object mesh = gmsh_to_meshio(gmsh) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index d71d7d34..aff8a0b4 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -247,7 +247,7 @@ def ReadGMSH(fnames: list) -> meshio.Mesh: for elem in gmshIssue: print(hopout.warn(f'Wrong Gmsh order {elem[1]} for element {elem[0].replace(" ", "")}')) elemOrders = set([int(elem[1]) for elem in gmshIssue]) - hopout.error(f'Gmsh element order(s) {elemOrders} does not match requested mesh order {set([mesh_vars.nGeo])}') + hopout.error(f'Gmsh element order(s) {elemOrders} does not match requested mesh order { {mesh_vars.nGeo} }') # Convert Gmsh object to meshio object mesh = gmsh_to_meshio(gmsh) From 05251c0cc7b9e9e64bf894ed78698fa4d9f5c191 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:14:13 +0100 Subject: [PATCH 24/59] Linting: Fix unnecessary-list-comprehension-set (C403) --- pyhope/basis/basis_connect.py | 6 +-- pyhope/basis/basis_jacobian.py | 4 +- pyhope/basis/basis_watertight.py | 4 +- pyhope/io/io_debug.py | 6 +-- pyhope/mesh/connect/connect.py | 12 +++--- pyhope/mesh/mesh_builtin.py | 2 +- pyhope/mesh/mesh_common.py | 58 ++++++++++++++--------------- pyhope/mesh/mesh_mortar.py | 2 +- pyhope/mesh/reader/reader_gambit.py | 4 +- pyhope/mesh/reader/reader_gmsh.py | 2 +- pyhope/mesh/reader/reader_hopr.py | 2 +- 11 files changed, 51 insertions(+), 51 deletions(-) diff --git a/pyhope/basis/basis_connect.py b/pyhope/basis/basis_connect.py index 5d6957a5..cf157d43 100644 --- a/pyhope/basis/basis_connect.py +++ b/pyhope/basis/basis_connect.py @@ -83,7 +83,7 @@ def check_sides(elem, # Sanity check the flip with the other nodes elem0 = elems[side[0].elemID] elem1 = elems[side[1].elemID] - if elem1.type % 100 != 8: + if elem1.type % 10 != 8: continue # Map the meshio nodes to the tensor-product nodes @@ -157,8 +157,8 @@ def CheckConnect() -> None: elems: Final[list] = mesh_vars.elems # Only consider hexahedrons - if any(cast(int, e.type) % 100 != 8 for e in elems): - elemTypes = list(set([e.type for e in elems if e.type % 100 != 8])) + if any(cast(int, e.type) % 10 != 8 for e in elems): + elemTypes = list({e.type for e in elems if e.type % 10 != 8}) print(hopout.warn('Ignored element type: {}'.format( [re.sub(r"\d+$", "", mesh_vars.ELEMTYPE.inam[e][0]) for e in elemTypes] ))) diff --git a/pyhope/basis/basis_jacobian.py b/pyhope/basis/basis_jacobian.py index 75912829..b3cf320d 100644 --- a/pyhope/basis/basis_jacobian.py +++ b/pyhope/basis/basis_jacobian.py @@ -155,7 +155,7 @@ def CheckJacobians() -> None: nGeo: Final[int] = mesh_vars.nGeo + 1 elems: Final[list] = mesh_vars.elems nodes: Final[npt.NDArray[np.float64]] = mesh_vars.mesh.points - elemBases: Final[set] = set([e.type % 100 for e in elems]) + elemBases: Final[set] = {e.type % 10 for e in elems} # Compute the equidistant point set used by meshIO xEq_fn = {4: lambda: equi_nodes_tetra(nGeo), # Tetrahedron @@ -213,7 +213,7 @@ def CheckJacobians() -> None: for elem in elems: elemType = elem.type - elemBase = int(elemType) % 100 + elemBase = int(elemType) % 10 # Get the mapping mapLin = linCache[elemType] diff --git a/pyhope/basis/basis_watertight.py b/pyhope/basis/basis_watertight.py index 5f99adde..0c421fcb 100644 --- a/pyhope/basis/basis_watertight.py +++ b/pyhope/basis/basis_watertight.py @@ -288,8 +288,8 @@ def CheckWatertight() -> None: # checked = np.zeros((len(sides)), dtype=bool) # Only consider hexahedrons - if any(e.type % 100 != 8 for e in elems): - elemTypes = list(set([e.type for e in elems if e.type % 100 != 8])) + if any(e.type % 10 != 8 for e in elems): + elemTypes = list({e.type for e in elems if e.type % 10 != 8}) print(hopout.warn('Ignored element type: {}'.format( [re.sub(r"\d+$", "", mesh_vars.ELEMTYPE.inam[e][0]) for e in elemTypes] ))) diff --git a/pyhope/io/io_debug.py b/pyhope/io/io_debug.py index 47c57f26..7e547829 100644 --- a/pyhope/io/io_debug.py +++ b/pyhope/io/io_debug.py @@ -115,7 +115,7 @@ def DebugIO() -> None: # Loop over all elements for melem in melems: # Correct ElemType for NGeo = 1 - elemNum = melem.type % 100 + elemNum = melem.type % 10 elemType = elemTypeClass.inam[elemNum + 100] elemType = ''.join(elemType) if isinstance(elemType, list) else elemType if elemType not in tInv: @@ -132,7 +132,7 @@ def DebugIO() -> None: sidetypes.add(sideType) # Create ordered mapping from first-order points to high-order points - points = np.concatenate([np.asarray(melem.nodes)[:melem.type % 100] for melem in melems]) + points = np.concatenate([np.asarray(melem.nodes)[:melem.type % 10] for melem in melems]) pMap = np.unique(points) # pInv = dict(zip(pMap, range(len(pMap)))) @@ -187,7 +187,7 @@ def DebugIO() -> None: # Populate connectivity and data for melem in melems: # Correct ElemType for NGeo = 1 - elemNum = melem.type % 100 + elemNum = melem.type % 10 elemType = elemTypeClass.inam[elemNum + 100] elemType = ''.join(elemType) if isinstance(elemType, list) else elemType elemZone = int(melem.zone) if (melem.zone is not None and isValidInt(melem.zone)) else 1 diff --git a/pyhope/mesh/connect/connect.py b/pyhope/mesh/connect/connect.py index 9678f4e1..7fd927d0 100644 --- a/pyhope/mesh/connect/connect.py +++ b/pyhope/mesh/connect/connect.py @@ -159,7 +159,7 @@ def periodic_update(sides: tuple, elems: tuple, vv: npt.NDArray) -> None: from pyhope.mesh.mesh_common import sidetovol2 # ------------------------------------------------------ # Periodic corrections are only supported for hexahedral elements - if elems[0].type % 100 != 8 or elems[1].type % 100 != 8: + if elems[0].type % 10 != 8 or elems[1].type % 10 != 8: return nGeo: Final[int] = mesh_vars.nGeo @@ -408,8 +408,8 @@ def ConnectMesh() -> None: case 2: # Internal side sideIDs = val # Flip pyramids - # if elems[sides[sideIDs[0]].elemID].type % 100 != 5 and \ - # elems[sides[sideIDs[1]].elemID].type % 100 == 5: + # if elems[sides[sideIDs[0]].elemID].type % 10 != 5 and \ + # elems[sides[sideIDs[1]].elemID].type % 10 == 5: # sideIDs = sideIDs[::-1] side0 = sides[sideIDs[0]] @@ -434,7 +434,7 @@ def ConnectMesh() -> None: # Sanity check the flip with the other nodes # > INFO: MOVED TO OWN CHECKCONNECT ROUTINE # elem = (elems[side0.elemID], elems[side1.elemID]) - # if elem[0].type % 100 == 8 and elem[1].type % 100 == 8: + # if elem[0].type % 10 == 8 and elem[1].type % 10 == 8: # # Map the meshio nodes to the tensor-product nodes # elemType = elem[0].type # nodes = elem[0].nodes[sidetovol2(nGeo, 0 , side0.face, elemType)] @@ -473,7 +473,7 @@ def ConnectMesh() -> None: locElems = tuple(elems[s.elemID] for s in locSides) # Only update hexahedral elements - if any(e.type % 100 != 8 for e in locElems): + if any(e.type % 10 != 8 for e in locElems): for e in locElems: passedTypes[e.type] = passedTypes.get(e.type, 0) + 1 else: @@ -507,7 +507,7 @@ def ConnectMesh() -> None: elem = elems[side.elemID] # nodes = elem.nodes[sidetovol2(nGeo, 0 , side.face, elem.type)] nodes = np.transpose(np.array([elem.nodes[s] for s in face_to_nodes(side.face, elem.type, nGeo)])) - if elem.type % 100 == 8: + if elem.type % 10 == 8: nodes = np.transpose(points[nodes] , axes=(2, 0, 1)) print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in nodes[:, 0, 0]) + ']')) print(hopout.warn('- Coordinates : [' + ' '.join(f'{s:13.8f}' for s in nodes[:, 0, -1]) + ']')) diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index 9b9a99ce..ec073708 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -393,7 +393,7 @@ def MeshCartesian() -> meshio.Mesh: if gmshIssue.size > 0: for elem in gmshIssue: print(hopout.warn(f'Wrong Gmsh order {elem[1]} for element {elem[0].replace(" ", "")}')) - elemOrders = set([int(elem[1]) for elem in gmshIssue]) + elemOrders = {int(elem[1]) for elem in gmshIssue} hopout.error(f'Gmsh element order(s) {elemOrders} does not match requested mesh order { {mesh_vars.nGeo} }') # Convert Gmsh object to meshio object diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index 9152f6c0..4af36f54 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -68,10 +68,10 @@ def faces(elemType: Union[int, str]) -> tuple[str, ...]: if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in faces: elemType {elemType} is not supported') - return faces_map[elemType % 100] + return faces_map[elemType % 10] @cache @@ -91,10 +91,10 @@ def edges(elemType: Union[int, str]) -> tuple[int, ...]: if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in edges_map: + if elemType % 10 not in edges_map: raise ValueError(f'Error in edges: elemType {elemType} is not supported') - return edges_map[elemType % 100] + return edges_map[elemType % 10] @cache @@ -114,10 +114,10 @@ def edge_to_dir(edge: int, elemType: Union[int, str]) -> int: if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in dir_map: + if elemType % 10 not in dir_map: raise ValueError(f'Error in edge_to_dir: elemType {elemType} is not supported') - dir = dir_map[elemType % 100] + dir = dir_map[elemType % 10] try: return (np.rint(abs(dir[edge]))).astype(int) @@ -147,10 +147,10 @@ def edge_to_corner(edge: int, elemType: Union[int, str], dtype=np.int32) -> npt. if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in edge_map: + if elemType % 10 not in edge_map: raise ValueError(f'Error in edge_to_corner: elemType {elemType} is not supported') - edges = edge_map[elemType % 100] + edges = edge_map[elemType % 10] try: return np.array(edges[edge], dtype=dtype) @@ -173,10 +173,10 @@ def edge_to_sign(edge: int, elemType: Union[int, str], dtype=np.float64) -> npt. if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in edge_map: + if elemType % 10 not in edge_map: raise ValueError(f'Error in edge_to_sign: elemType {elemType} is not supported') - edges = edge_map[elemType % 100] + edges = edge_map[elemType % 10] try: return np.array(edges[edge], dtype=dtype) @@ -203,11 +203,11 @@ def face_to_edge(face: str, elemType: Union[str, int], dtype=np.int32) -> npt.ND if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in face_to_edge: elemType {elemType} is not supported') try: - return faces_map[elemType % 100][face] + return faces_map[elemType % 10][face] except KeyError as e: raise KeyError(f'Error in face_to_edge: face {face} is not supported') from e @@ -231,11 +231,11 @@ def face_to_corner(face, elemType: Union[str, int], dtype=np.int32) -> npt.NDArr if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in face_to_corner: elemType {elemType} is not supported') try: - return faces_map[elemType % 100][face] + return faces_map[elemType % 10][face] except KeyError as e: raise KeyError(f'Error in face_to_corner: face {face} is not supported') from e @@ -273,11 +273,11 @@ def face_to_cgns(face: str, elemType: Union[str, int], dtype=np.int32) -> npt.ND if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in face_to_cgns: elemType {elemType} is not supported') try: - return faces_map[elemType % 100][face] + return faces_map[elemType % 10][face] except KeyError as e: raise KeyError(f'Error in face_to_cgns: face {face} is not supported') from e @@ -386,11 +386,11 @@ def flip_s2m(N: int, p: int, q: int, flip: int, elemType: Union[str, int], dtype if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in flip_map: + if elemType % 10 not in flip_map: raise ValueError(f'Error in flip_s2m: elemType {elemType} is not supported') try: - return flip_map[elemType % 100][flip] + return flip_map[elemType % 10][flip] except KeyError as e: raise KeyError(f'Error in flip_s2m: face {flip} is not supported') from e @@ -414,11 +414,11 @@ def cgns_sidetovol(N: int, r: int, p: int, q: int, face: str, elemType: Union[st if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in cgns_sidetovol: elemType {elemType} is not supported') try: - return faces_map[elemType % 100][face] + return faces_map[elemType % 10][face] except KeyError as e: raise KeyError(f'Error in cgns_sidetovol: face {face} is not supported') from e @@ -468,11 +468,11 @@ def type_to_mortar_flip(elemType: Union[int, str]) -> dict[int, dict[int, int]]: if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in flipID_map: + if elemType % 10 not in flipID_map: raise ValueError(f'Error in type_to_mortar_flip: elemType {elemType} is not supported') try: - return flipID_map[elemType % 100] + return flipID_map[elemType % 10] except KeyError as e: raise KeyError(f'Error in type_to_mortar_flip: elemType {elemType} is not supported') from e @@ -521,15 +521,15 @@ def face_to_nodes(face: str, elemType: int, nGeo: int, dtype=np.int32) -> npt.ND # 'z+': np.transpose(LINMAP(108 if order == 1 else 208, order=order)[: , : , order])} # noqa: E272, E501 # # } - # if elemType % 100 not in faces_map: + # if elemType % 10 not in faces_map: # raise ValueError(f'Error in face_to_nodes: elemType {elemType} is not supported') # # try: - # return faces_map[elemType % 100][face] + # return faces_map[elemType % 10][face] # except KeyError as e: # raise KeyError(f'Error in face_to_cgns: face {face} is not supported') from e - match elemType % 100: + match elemType % 10: case 4: # Tetrahedron faces_map = { # Sides aligned with the axes 'z-': [s for s in LINMAP(104 if order == 1 else 204, order=order)[: , : , 0 ].flatten() if s != -1], # noqa: E272, E501 @@ -608,11 +608,11 @@ def dir_to_nodes(dir: str, elemType: Union[str, int], nGeo: int) -> tuple[Any, b 'x-': ((0 , slice(None), slice(None)), False), # elemNodes[0 , : , : ], # noqa: E262, E501 'z+': ((slice(None), slice(None), order ), True )} # np.transpose(elemNodes[: , : , order])} # noqa: E262, E501 } - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in face_to_cgns: elemType {elemType} is not supported') try: - return faces_map[elemType % 100][dir] + return faces_map[elemType % 10][dir] except KeyError as e: raise KeyError(f'Error in dir_to_nodes: face {dir} is not supported') from e @@ -849,10 +849,10 @@ def NDOFS_ELEM(elemType: int, N: int, dim: int = 3) -> int: 8: (N+1)**dim } - if elemType % 100 not in nodes_map: + if elemType % 10 not in nodes_map: raise ValueError(f'Error in nodes: elemType {elemType} is not supported') - return nodes_map[elemType % 100] + return nodes_map[elemType % 10] @cache diff --git a/pyhope/mesh/mesh_mortar.py b/pyhope/mesh/mesh_mortar.py index 168c38c3..9b2627ae 100644 --- a/pyhope/mesh/mesh_mortar.py +++ b/pyhope/mesh/mesh_mortar.py @@ -85,7 +85,7 @@ def RebuildMortarGeometry() -> None: vvs: Final[list ] = mesh_vars.vvs # Rebuilding mortar geometries is only supported for hexahedral meshes - if any([s != 8 for s in set([e.type % 100 for e in elems])]): + if any([s != 8 for s in {e.type % 10 for e in elems}]): return None hopout.sep() diff --git a/pyhope/mesh/reader/reader_gambit.py b/pyhope/mesh/reader/reader_gambit.py index 22384ffe..381e50a4 100644 --- a/pyhope/mesh/reader/reader_gambit.py +++ b/pyhope/mesh/reader/reader_gambit.py @@ -60,10 +60,10 @@ def gambit_faces(elemType: Union[int, str]) -> list[str]: if isinstance(elemType, str): elemType = elemTypeClass.name[elemType] - if elemType % 100 not in faces_map: + if elemType % 10 not in faces_map: raise ValueError(f'Error in faces: elemType {elemType} is not supported') - return faces_map[elemType % 100] + return faces_map[elemType % 10] def ReadGambit(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index aff8a0b4..3317bc8a 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -246,7 +246,7 @@ def ReadGMSH(fnames: list) -> meshio.Mesh: if gmshIssue.size > 0: for elem in gmshIssue: print(hopout.warn(f'Wrong Gmsh order {elem[1]} for element {elem[0].replace(" ", "")}')) - elemOrders = set([int(elem[1]) for elem in gmshIssue]) + elemOrders = {int(elem[1]) for elem in gmshIssue} hopout.error(f'Gmsh element order(s) {elemOrders} does not match requested mesh order { {mesh_vars.nGeo} }') # Convert Gmsh object to meshio object diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index bda78122..57625a84 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -177,7 +177,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: # Construct the elements, meshio format for elem in elemInfo: # Correct ElemType if NGeo is changed - elemNum = elem[0] % 100 + elemNum = elem[0] % 10 elemNum += 200 if mesh_vars.nGeo > 1 else 100 # Obtain the element type From bb21cb44a708f69865ae57d160bf05012546b6f7 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:15:06 +0100 Subject: [PATCH 25/59] Linting: Ignore open-file-with-context-handler (SIM115) --- pyhope/mesh/reader/reader_gmsh.py | 2 +- pyhope/mesh/reader/reader_hopr.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 3317bc8a..6a648ee4 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -345,7 +345,7 @@ def BCCGNS(mesh: meshio.Mesh, fnames: list) -> meshio.Mesh: for fname in fnames: # Create a temporary directory and keep it existing until manually cleaned - tfile = tempfile.NamedTemporaryFile(delete=False) + tfile = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115 tname = tfile.name # Try to convert the file automatically if not h5py.is_hdf5(fname): diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index 57625a84..bb47c34f 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -87,7 +87,7 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: hopout.error(f'[󰇘]/{os.path.basename(fname)} is not in HDF5 format, exiting...') # Create a temporary directory and keep it existing until manually cleaned - tfile = tempfile.NamedTemporaryFile(delete=False) + tfile = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115 tname = tfile.name # Alternatively, load the file directly into tmpfs for faster access shutil.copyfile(fname, tname) From c01b36f72bb1d3e11c86024e917932278fce967a Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:16:18 +0100 Subject: [PATCH 26/59] Linting: Fix unnecessary-comprehension-in-call (C419) --- pyhope/mesh/mesh_mortar.py | 2 +- pyhope/mesh/reader/reader_gmsh.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/mesh_mortar.py b/pyhope/mesh/mesh_mortar.py index 9b2627ae..3560ca5f 100644 --- a/pyhope/mesh/mesh_mortar.py +++ b/pyhope/mesh/mesh_mortar.py @@ -85,7 +85,7 @@ def RebuildMortarGeometry() -> None: vvs: Final[list ] = mesh_vars.vvs # Rebuilding mortar geometries is only supported for hexahedral meshes - if any([s != 8 for s in {e.type % 10 for e in elems}]): + if any(s != 8 for s in {e.type % 10 for e in elems}): return None hopout.sep() diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 6a648ee4..76c503de 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -228,7 +228,7 @@ def ReadGMSH(fnames: list) -> meshio.Mesh: gmshTypes = gmsh.model.mesh.getElementTypes() gmshElems = np.asarray([(elemName, dim, order) for type in gmshTypes # noqa: E272 for elemName, dim, order, _, _, _ in [gmsh.model.mesh.getElementProperties(type)]]) # noqa: E501 - gmshDim = max([int(s) for s in gmshElems[:, 1]]) + gmshDim = max(int(s) for s in gmshElems[:, 1]) match gmshDim: case 3: pass From 62cc374b5f453413c77c4e37ce23956de8f7d180 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:17:47 +0100 Subject: [PATCH 27/59] Linting: Fix self-assigning-variable (PLW0127) --- pyhope/mesh/reader/reader_gambit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/reader/reader_gambit.py b/pyhope/mesh/reader/reader_gambit.py index 381e50a4..ea9ce1f1 100644 --- a/pyhope/mesh/reader/reader_gambit.py +++ b/pyhope/mesh/reader/reader_gambit.py @@ -237,8 +237,8 @@ def ReadGambit(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: continue try: - bcName, bcType, bcnData, bcnVal, _ = tokens - bcName, bcType, bcnData, bcnVal = bcName, int(bcType), int(bcnData), int(bcnVal) + bcName, *ints, _ = tokens + bcType, bcnData, _ = map(int, ints) except ValueError: continue From bca7b443af89d591fc40c15e09b11d74ffdacc9a Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:29:39 +0100 Subject: [PATCH 28/59] Linting: Ignore mutable-class-default (RUF012) --- pyhope/common/common_vars.py | 4 ++-- pyhope/io/io_gmsh.py | 4 ++-- pyhope/mesh/mesh_vars.py | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyhope/common/common_vars.py b/pyhope/common/common_vars.py index ca994032..efdf9695 100644 --- a/pyhope/common/common_vars.py +++ b/pyhope/common/common_vars.py @@ -144,7 +144,7 @@ class Gitlab: LIB_GITLAB: str = 'gitlab.iag.uni-stuttgart.de' # LIB_PROJECT = 'libs/python-gmsh' LIB_PROJECT: str = '797' - LIB_VERSION: dict[str, dict[str, str]] = { + LIB_VERSION: dict[str, dict[str, str]] = { # noqa: RUF012 'linux': { 'x86_64' : '4.15.1.post1', 'aarch64': '4.13.1.post1' @@ -153,7 +153,7 @@ class Gitlab: 'arm64' : '4.13.1.post1' }, } - LIB_SUPPORT: dict[str, dict[str, str]] = { + LIB_SUPPORT: dict[str, dict[str, str]] = { # noqa: RUF012 'linux': { 'x86_64' : '4f2b923a164f8f8b77494df943ea52a3f7050716f9b9cbac9190f7460ca822fb', 'aarch64': '104fe49eeb75ee91cb237acd251533aae98fb48c7e4e16517be6c0f4ccf677da' diff --git a/pyhope/io/io_gmsh.py b/pyhope/io/io_gmsh.py index ee37721f..8260a6c7 100644 --- a/pyhope/io/io_gmsh.py +++ b/pyhope/io/io_gmsh.py @@ -44,7 +44,7 @@ class GMSHCELLTYPES: Reference: http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format ''' - cellTypes3D = [ 'tetra' , 'hexahedron' , 'wedge' , 'pyramid', # NGeo = 1 # noqa: E501 + cellTypes3D = [ 'tetra' , 'hexahedron' , 'wedge' , 'pyramid', # NGeo = 1 # noqa: E501, RUF012 'tetra10' , 'hexahedron20' , 'hexahedron24', 'hexahedron27', 'wedge15', 'wedge18', 'pyramid13', 'pyramid14', # NGeo = 2 # noqa: E501 'tetra20' , 'hexahedron64' , 'wedge40', # NGeo = 3 # noqa: E501 'tetra35' , 'hexahedron125' , 'wedge75', # NGeo = 4 # noqa: E501 @@ -55,7 +55,7 @@ class GMSHCELLTYPES: 'tetra220', 'hexahedron1000', 'wedge550', # NGeo = 9 # noqa: E501 'tetra286', 'hexahedron1331' # NGeo = 10 # noqa: E501 ] - cellTypes2D = [ 'triangle' , 'quad' , # NGeo = 1 # noqa: E501 + cellTypes2D = [ 'triangle' , 'quad' , # NGeo = 1 # noqa: E501, RUF012 'triangle6' , 'quad8' , 'quad9', # NGeo = 2 # noqa: E501 'triangle10', 'quad16' , # NGeo = 3 # noqa: E501 'triangle15', 'quad25' , # NGeo = 4 # noqa: E501 diff --git a/pyhope/mesh/mesh_vars.py b/pyhope/mesh/mesh_vars.py index e39e3c2f..9d21ac7d 100644 --- a/pyhope/mesh/mesh_vars.py +++ b/pyhope/mesh/mesh_vars.py @@ -276,11 +276,11 @@ class BC: @final class ELEMTYPE: - type = {'tetra' : 4, + type = {'tetra' : 4, # noqa: RUF012 'pyramid' : 5, 'wedge' : 5, 'hexahedron': 6} - name = {'tetra' : 104, 'tetra10' : 204, 'tetra20' : 204, 'tetra35' : 204, 'tetra56' : 204, + name = {'tetra' : 104, 'tetra10' : 204, 'tetra20' : 204, 'tetra35' : 204, 'tetra56' : 204, # noqa: RUF012 'tetra84' : 204, 'tetra120' : 204, 'tetra165' : 204, 'tetra220' : 204, 'tetra286' : 204, 'pyramid' : 105, 'pyramid13' : 205, 'pyramid14' : 205, 'pyramid30' : 205, 'pyramid55' : 205, @@ -290,7 +290,7 @@ class ELEMTYPE: 'hexahedron': 108, 'hexahedron20' : 208, 'hexahedron24' : 208, 'hexahedron27' : 208, 'hexahedron64' : 208, 'hexahedron125': 208, 'hexahedron216' : 208, 'hexahedron343' : 208, 'hexahedron512' : 208, 'hexahedron729': 208, 'hexahedron1000': 208, 'hexahedron1331': 208} - inam = defaultdict(list) + inam = defaultdict(list) # noqa: RUF012 for key, value in name.items(): inam[value].append(key) From 12ecf3894e8076bb9fd37d25a65febbcf910084b Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:30:25 +0100 Subject: [PATCH 29/59] Linting: Fix quoted-annotation (UP037) --- pyhope/mesh/mesh_vars.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyhope/mesh/mesh_vars.py b/pyhope/mesh/mesh_vars.py index 9d21ac7d..fe002ec4 100644 --- a/pyhope/mesh/mesh_vars.py +++ b/pyhope/mesh/mesh_vars.py @@ -53,13 +53,13 @@ mesh : meshio.Mesh # MeshIO object holding the mesh nGeo : int # Order of spline-reconstruction for curved surfaces -bcs : list[Optional['BC']] # [list of dict] - Boundary conditions +bcs : list[Optional[BC]] # [list of dict] - Boundary conditions vvs : list # [list of dict] - Periodic vectors nZones : int = 1 # Number of zones elemTypes: list[int] = [] # Element types per zone -elems : list[Optional['ELEM']] # [list of list] - Element nodes -sides : list[Optional['SIDE']] # [list of list] - Side nodes +elems : list[Optional[ELEM]] # [list of list] - Element nodes +sides : list[Optional[SIDE]] # [list of list] - Side nodes # Periodic nodes periNodes: dict # Mapping from the periodic nodes to the master nodes From a3b378244f5cac9f3306f6b262a5a7ecd1527398 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:31:04 +0100 Subject: [PATCH 30/59] Linting: Fix unsorted-dunder-slots (RUF023) --- pyhope/common/common_progress.py | 2 +- pyhope/mesh/connect/connect_rbtree.py | 4 ++-- pyhope/mesh/mesh_sort.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyhope/common/common_progress.py b/pyhope/common/common_progress.py index ebf21156..c9aba3b6 100644 --- a/pyhope/common/common_progress.py +++ b/pyhope/common/common_progress.py @@ -44,7 +44,7 @@ class ProgressBar: """ Provide a progress bar outside of the context manager """ - __slots__ = ('bar', '_cm', '_len', '_cur', '_chunk', '_pend') + __slots__ = ('_chunk', '_cm', '_cur', '_len', '_pend', 'bar') def __init__(self, title : Optional[str], diff --git a/pyhope/mesh/connect/connect_rbtree.py b/pyhope/mesh/connect/connect_rbtree.py index b48fcfaf..68e351e2 100644 --- a/pyhope/mesh/connect/connect_rbtree.py +++ b/pyhope/mesh/connect/connect_rbtree.py @@ -128,7 +128,7 @@ class SideNode: # """ # value = SIDE # link = Optional[int] # This is the base (stored) connection value - __slots__ = ('value', 'link') + __slots__ = ('link', 'value') def __init__(self, value: SIDE, @@ -178,7 +178,7 @@ class RedBlackTree: """ This class provides a balanced binary search tree implemented as a Red-Black Tree, augmented with subtree sizes to support efficient arbitrary insertions and random access """ - __slots__ = ('_root', '_size', 'offset_manager', '_node_at') + __slots__ = ('_node_at', '_root', '_size', 'offset_manager') def __init__(self, offset_manager: LinkOffsetManager) -> None: diff --git a/pyhope/mesh/mesh_sort.py b/pyhope/mesh/mesh_sort.py index 5ab4e182..12cf1a91 100644 --- a/pyhope/mesh/mesh_sort.py +++ b/pyhope/mesh/mesh_sort.py @@ -122,7 +122,7 @@ def UpdateElemID(elems : list, @final class tBox: - __slots__ = ('mini', 'intfact', 'spacing') + __slots__ = ('intfact', 'mini', 'spacing') def __init__(self, mini: int, maxi: int): self.mini = mini From 9a9a64b73d7cbfd31d7602acfbacc69d00fcd62b Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:31:51 +0100 Subject: [PATCH 31/59] Linting: Ignore native-literals (UP018) --- pyhope/mesh/mesh_builtin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index ec073708..6bce3639 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -102,7 +102,7 @@ def MeshCartesian() -> meshio.Mesh: hopout.sep() nZones = GetInt('nZones') - elemTypes = [int() for _ in range(nZones)] + elemTypes = [int() for _ in range(nZones)] # noqa: UP018 offsetp = 0 offsets = 0 From 92c17929c387a8d71ad1eedb64fcfa6ff5cde761 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:32:29 +0100 Subject: [PATCH 32/59] Linting: Fix unnecessary-double-cast-or-process (C414) --- pyhope/check/check_health.py | 2 +- pyhope/mesh/fem/fem.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/check/check_health.py b/pyhope/check/check_health.py index e8dc457d..6c22e0ad 100644 --- a/pyhope/check/check_health.py +++ b/pyhope/check/check_health.py @@ -339,7 +339,7 @@ def CheckHealth() -> None: # For optional dependencies, split the first part opts = [p.split(';')[0] for p in pkgs if len(p.split(';')) > 1] # noqa: E272 - all_pkg_names = sorted(list(set([program] + [_PackageExtractName(p) for p in deps + opts]))) + all_pkg_names = sorted(set([program] + [_PackageExtractName(p) for p in deps + opts])) # Fetch all versions in parallel with ThreadPoolExecutor(max_workers=10) as executor: diff --git a/pyhope/mesh/fem/fem.py b/pyhope/mesh/fem/fem.py index 539ba61b..2c81b3bc 100644 --- a/pyhope/mesh/fem/fem.py +++ b/pyhope/mesh/fem/fem.py @@ -171,7 +171,7 @@ def FEMConnect() -> None: # > are displaced by each periodic boundary condition. We build a simple, directed # > map for each BC that directly reflects the (source -> target) relationship in # > periNodes. We only want to map from negative to positive, thus keep the direction - periNames = sorted(list({bc for _, bc in periNodes})) + periNames = sorted({bc for _, bc in periNodes}) # This dictionary holds the directed mapping for each BC # > Key: Source node From 250934d416934051ca662cd040be1f13f09ec40c Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:39:34 +0100 Subject: [PATCH 33/59] Linting: Fix cached-instance-method (B019) --- pyhope/common/common_vars.py | 3 --- pyhope/mesh/connect/connect_rbtree.py | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pyhope/common/common_vars.py b/pyhope/common/common_vars.py index efdf9695..7f9105f5 100644 --- a/pyhope/common/common_vars.py +++ b/pyhope/common/common_vars.py @@ -32,7 +32,6 @@ import subprocess from collections.abc import Callable from enum import Enum, unique -from functools import cache from typing import Final, Optional, final from typing_extensions import Self # ---------------------------------------------------------------------------------------------------------------------------------- @@ -78,7 +77,6 @@ def __init__(self: Self) -> None: self._commit: Final = self.__commit__ @property - @cache def __version__(self) -> Version: # Retrieve version from package metadata try: @@ -99,7 +97,6 @@ def __version__(self) -> Version: return Version(version) @property - @cache def __commit__(self) -> Optional[str]: # Retrieve commit from git try: diff --git a/pyhope/mesh/connect/connect_rbtree.py b/pyhope/mesh/connect/connect_rbtree.py index 68e351e2..ffd73477 100644 --- a/pyhope/mesh/connect/connect_rbtree.py +++ b/pyhope/mesh/connect/connect_rbtree.py @@ -105,7 +105,7 @@ def update(self, # Clear any cached offset computations self.get_offset.cache_clear() - @cache + @cache # noqa: B019 def get_offset(self, index: int) -> int: """ Cached offset lookup for stored index. @@ -284,7 +284,7 @@ def _insert_fixup(self, z: _RBTreeNode) -> None: self._left_rotate(cast(_RBTreeNode, z.parent.parent)) self._root.color = BLACK - @lru_cache(maxsize=4096) + @lru_cache(maxsize=4096) # noqa: B019 def _node_at_impl(self, index: int) -> SideNode: if not 0 <= index < self._size: raise IndexError('Index out of range') From ecab4a62d4daa1022cc76a0e3d535f7cacf6f9ee Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:40:00 +0100 Subject: [PATCH 34/59] Linting: Fix if-else-block-instead-of-dict-get (SIM401) --- pyhope/mesh/connect/connect_mortar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index 51b19178..1cafef8e 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -146,7 +146,7 @@ def ConnectMortar( nConnSide : list # Shift the center in periodic direction targetCenters[nConnID] += VV - targetCorners[nConnID, :] = np.array([periNodes[(s, bcName)] if (s, bcName) in periNodes else s for s in side.corners]) + targetCorners[nConnID, :] = np.array([periNodes.get((s, bcName), s) for s in side.corners]) # Calculate the radius of the convex hull targetRadius[nConnID] = norm(np.ptp(points[side.corners], axis=0)) / 2. From d38e8d2edcc2f46a44f412a642f5494eaa7cf484 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:44:07 +0100 Subject: [PATCH 35/59] Linting: Fix if-expr-with-true-false (SIM210) --- pyhope/io/formats/meshio.py | 1 - pyhope/io/io_debug.py | 4 ++-- pyhope/mesh/connect/connect.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pyhope/io/formats/meshio.py b/pyhope/io/formats/meshio.py index c28c7284..e8c8779b 100644 --- a/pyhope/io/formats/meshio.py +++ b/pyhope/io/formats/meshio.py @@ -357,7 +357,6 @@ def PRISMAPMESHIO(order: int) -> tuple[npt.NDArray, npt.NDArray]: map[3, 1, 2] = count+8 map[2, 2, 2] = count+9 count += 9 - # if order == 4: map[0, 2, 1] = count+1 map[0, 1, 1] = count+2 diff --git a/pyhope/io/io_debug.py b/pyhope/io/io_debug.py index 7e547829..09a03e47 100644 --- a/pyhope/io/io_debug.py +++ b/pyhope/io/io_debug.py @@ -136,8 +136,8 @@ def DebugIO() -> None: pMap = np.unique(points) # pInv = dict(zip(pMap, range(len(pMap)))) - hasIJK = True if hasattr(mesh_vars, 'nElemsIJK' ) and mesh_vars.nElemsIJK is not None else False # noqa: E272 - hasFEM = True if hasattr(melems[0], 'vertexInfo') and melems[0].vertexInfo is not None else False + hasIJK = bool(hasattr(mesh_vars, 'nElemsIJK') and mesh_vars.nElemsIJK is not None) # noqa: E272 + hasFEM = bool(hasattr(melems[0], 'vertexInfo') and melems[0].vertexInfo is not None) # Prepare element and side containers for t in elemtypes: diff --git a/pyhope/mesh/connect/connect.py b/pyhope/mesh/connect/connect.py index 7fd927d0..cbd71272 100644 --- a/pyhope/mesh/connect/connect.py +++ b/pyhope/mesh/connect/connect.py @@ -493,7 +493,7 @@ def ConnectMesh() -> None: nConnSide, nConnCenter = get_nonconnected_sides(sides, mesh) # Mortar sides - mesh_vars.hasMortars = True if len(nConnSide) > 0 else False + mesh_vars.hasMortars = len(nConnSide) > 0 if doMortars: # Connect the mortar sides From 4fdd99dcfeaf5d82b8a31efd4afa01be904c9ed0 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:46:56 +0100 Subject: [PATCH 36/59] Linting: Fix multiple-with-statements (SIM117) --- pyhope/__init__.py | 55 +++++++++++++++++------------------ pyhope/check/check_install.py | 7 ++--- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/pyhope/__init__.py b/pyhope/__init__.py index eb2fdd35..44bf4bee 100644 --- a/pyhope/__init__.py +++ b/pyhope/__init__.py @@ -150,34 +150,33 @@ def Mesh(*args: str, stdout: bool = False, stderr: bool = True): raise ValueError(f'Mesh file not a valid HDF5 file: {arg}') # Suppress output to standard output - with ExitStack() as stack: - with open(os.devnull, 'w') as null: - if not stdout: - stack.enter_context(redirect_stdout(null)) - if not stderr: - stack.enter_context(redirect_stderr(null)) - - # Perform the reduced PyHOPE initialization - with DefineConfig() as dc: - config.prms = dc - DefineCommon() - DefineIO() - DefineMesh() - - with ReadConfig(args[0]) as rc: - config.params = rc - - # Read-in required parameters - InitCommon() - InitIO() - InitMesh() - - # Generate the actual mesh - GenerateMesh() - - # Build our data structures - GenerateSides() - ConnectMesh() + with ExitStack() as stack, open(os.devnull, 'w') as null: + if not stdout: + stack.enter_context(redirect_stdout(null)) + if not stderr: + stack.enter_context(redirect_stderr(null)) + + # Perform the reduced PyHOPE initialization + with DefineConfig() as dc: + config.prms = dc + DefineCommon() + DefineIO() + DefineMesh() + + with ReadConfig(args[0]) as rc: + config.params = rc + + # Read-in required parameters + InitCommon() + InitIO() + InitMesh() + + # Generate the actual mesh + GenerateMesh() + + # Build our data structures + GenerateSides() + ConnectMesh() # Export mesh variables mesh = mesh_vars.mesh diff --git a/pyhope/check/check_install.py b/pyhope/check/check_install.py index f98c0f66..ebce3d9f 100644 --- a/pyhope/check/check_install.py +++ b/pyhope/check/check_install.py @@ -275,10 +275,9 @@ def CheckInstall(path: Optional[str] = None) -> None: # Suppress output to standard output try: - with open(os.devnull, 'w') as null, redirect_stdout(null): - # All code that should have silent stdout here - with ReadConfig(parameter) as rc: - params = rc + # All code that should have silent stdout here + with open(os.devnull, 'w') as null, redirect_stdout(null), ReadConfig(parameter) as rc: + params = rc except Exception: # Config read failed bar.step() From 19d482dbbd4751d19704d3abc07f57691604e7fe Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:56:35 +0100 Subject: [PATCH 37/59] Linting: Fix function-uses-loop-variable (B023) --- pyhope/basis/basis_connect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyhope/basis/basis_connect.py b/pyhope/basis/basis_connect.py index cf157d43..67e8c0b2 100644 --- a/pyhope/basis/basis_connect.py +++ b/pyhope/basis/basis_connect.py @@ -95,7 +95,7 @@ def check_sides(elem, try: # Translate to periodic nodes if required if side[0].bcid is not None and side[1].bcid is not None and bcs[side[1].bcid].type[0] == 1: - nbNodes = np.vectorize(lambda s: mesh_vars.periNodes[(s, bcs[side[1].bcid].name)], otypes=[int])(nbNodes) + nbNodes = np.vectorize(lambda s, side=side: mesh_vars.periNodes[(s, bcs[side[1].bcid].name)], otypes=[int])(nbNodes) # Check if the node IDs match success = np.array_equal(nodes, nbNodes) # Fallback to comparison of physical coordinates From 395b3e68a717b553be8e68514d74203abe88fb9f Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:57:41 +0100 Subject: [PATCH 38/59] Linting: Fix subprocess-run-without-check (PLW1510) --- pyhope/check/check_health.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/check/check_health.py b/pyhope/check/check_health.py index 6c22e0ad..e9203d36 100644 --- a/pyhope/check/check_health.py +++ b/pyhope/check/check_health.py @@ -111,7 +111,7 @@ def GmshVersion() -> tuple[Union[Version, bool, None], Union[str, None]]: if path: try: - p = subprocess.run([path, '--info'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5) + p = subprocess.run([path, '--info'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5, check=True) raw = (p.stdout or '') + "\n" + (p.stderr or '') # Parse version from the Version line if present v = _ParseVersion(raw) @@ -172,7 +172,7 @@ def DependencyVersion(program: str) -> Optional[Version | bool]: if path: for flag in ('--version', '-V', 'version', '-v'): try: - p = subprocess.run([path, flag], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5) + p = subprocess.run([path, flag], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5, check=True) except Exception: continue From 734e3d36210cb77c65174a63ca6664c366e55e48 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 15:59:04 +0100 Subject: [PATCH 39/59] Linting: Fix replace-stdout-stderr (UP022) --- pyhope/check/check_health.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/check/check_health.py b/pyhope/check/check_health.py index e9203d36..4b5094eb 100644 --- a/pyhope/check/check_health.py +++ b/pyhope/check/check_health.py @@ -111,7 +111,7 @@ def GmshVersion() -> tuple[Union[Version, bool, None], Union[str, None]]: if path: try: - p = subprocess.run([path, '--info'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5, check=True) + p = subprocess.run([path, '--info'], capture_output=True, text=True, timeout=5, check=True) raw = (p.stdout or '') + "\n" + (p.stderr or '') # Parse version from the Version line if present v = _ParseVersion(raw) @@ -172,7 +172,7 @@ def DependencyVersion(program: str) -> Optional[Version | bool]: if path: for flag in ('--version', '-V', 'version', '-v'): try: - p = subprocess.run([path, flag], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5, check=True) + p = subprocess.run([path, flag], capture_output=True, text=True, timeout=5, check=True) except Exception: continue From d7628e0f8981b06df1db4709896fb7e58024dd6f Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:08:23 +0100 Subject: [PATCH 40/59] Linting: Fix zip-without-explicit-strict (B905) --- pyhope/check/check_health.py | 2 +- pyhope/io/io.py | 2 +- pyhope/mesh/connect/connect_mortar.py | 4 ++-- pyhope/mesh/mesh_external.py | 2 +- pyhope/mesh/mesh_mortar.py | 6 +++--- pyhope/mesh/topology/mesh_splittohex.py | 2 +- pyhope/meshio/meshio_convert.py | 10 +++++----- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pyhope/check/check_health.py b/pyhope/check/check_health.py index 4b5094eb..afc60190 100644 --- a/pyhope/check/check_health.py +++ b/pyhope/check/check_health.py @@ -349,7 +349,7 @@ def CheckHealth() -> None: # Query PyPI for all packages pypi_results = list(executor.map(PyPIVersion, all_pkg_names)) - pypi_map = dict(zip(all_pkg_names, pypi_results)) + pypi_map = dict(zip(all_pkg_names, pypi_results, strict=True)) # Display system and packages sections hopout.small_banner('System') diff --git a/pyhope/io/io.py b/pyhope/io/io.py index 6d1ec903..53090c91 100644 --- a/pyhope/io/io.py +++ b/pyhope/io/io.py @@ -292,7 +292,7 @@ def getMeshInfo() -> tuple[np.ndarray, # ElemInfo # Update element counter uniq_types, uniq_counts = np.unique(elem_types, return_counts=True) - for elemType, elemCount in zip(uniq_types, uniq_counts): + for elemType, elemCount in zip(uniq_types, uniq_counts, strict=True): elemCounter[elemType] = elemCount # Fill the IJK-sorting array diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index 1cafef8e..33360981 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -132,7 +132,7 @@ def ConnectMortar( nConnSide : list targetRadius = np.empty((nConn ), dtype=np.float64) targetArea = np.empty((nConn ), dtype=np.float64) - for nConnID, (side, center) in enumerate(zip(nConnSide, nConnCenter)): + for nConnID, (side, center) in enumerate(zip(nConnSide, nConnCenter, strict=True)): targetArea [nConnID ] = calculate_area(points[side.corners]) # noqa: E211 targetCenters[nConnID ] = copy.copy(center) targetCorners[nConnID, :] = side.corners @@ -154,7 +154,7 @@ def ConnectMortar( nConnSide : list # Get all potential mortar neighbors within the radius workers = 1 if np_mtp <= 0 else np_mtp results = ctree.query_ball_point(targetCenters, r=targetRadius[:], workers=workers) - for nConnID, (side, neighbors) in enumerate(zip(nConnSide, results)): + for nConnID, (side, neighbors) in enumerate(zip(nConnSide, results, strict=True)): targetNeighbors = tuple(s for s in neighbors # Potential mortar sides must not belong to the same element if nConnSide[s].elemID != side.elemID # noqa: E271, E501 diff --git a/pyhope/mesh/mesh_external.py b/pyhope/mesh/mesh_external.py index 9411ba24..a5c507f5 100644 --- a/pyhope/mesh/mesh_external.py +++ b/pyhope/mesh/mesh_external.py @@ -108,7 +108,7 @@ def MeshExternal() -> meshio.Mesh: minsize: Final[int] = 256 if any(s < minsize for s in fsizes): # Loop over the meshes and emit the warnings - for f, s in zip(fnames, fsizes): + for f, s in zip(fnames, fsizes, strict=True): print(hopout.warn(f'Mesh file "{os.path.basename(f)}" appears too small [{sizeof_fmt(s)}]. Continuing anyways...')) # Gmsh has to come first as we cannot extend the mesh diff --git a/pyhope/mesh/mesh_mortar.py b/pyhope/mesh/mesh_mortar.py index 3560ca5f..c0596e79 100644 --- a/pyhope/mesh/mesh_mortar.py +++ b/pyhope/mesh/mesh_mortar.py @@ -128,7 +128,7 @@ def RebuildMortarGeometry() -> None: mortarSides = tuple(sides[sides[side.sideID+i].connection] for i in range(1, 5)) mortarElems = tuple(elems[s.elemID] for s in mortarSides) # noqa: E272 - mortarNodes = tuple(e.nodes[sidetovol2(nGeo, s.flip, s.face, elemType)] for e, s in zip(mortarElems, mortarSides)) # noqa: E271, E272 + mortarNodes = tuple(e.nodes[sidetovol2(nGeo, s.flip, s.face, elemType)] for e, s in zip(mortarElems, mortarSides, strict=True)) # noqa: E271, E272, E501 mortarGeo = tuple(s.reshape((nGeo+1, nGeo+1), order='F') for s in mortarNodes) # noqa: E271, E272 # Interpolate big mortar side to small mortar sides @@ -173,7 +173,7 @@ def RebuildMortarGeometry() -> None: mortarSides = tuple(sides[sides[side.sideID+i].connection] for i in range(1, 3)) mortarElems = tuple(elems[s.elemID] for s in mortarSides) # noqa: E272 - mortarNodes = tuple(e.nodes[sidetovol2(nGeo, s.flip, s.face, elemType)] for e, s in zip(mortarElems, mortarSides)) # noqa: E271, E272 + mortarNodes = tuple(e.nodes[sidetovol2(nGeo, s.flip, s.face, elemType)] for e, s in zip(mortarElems, mortarSides, strict=True)) # noqa: E271, E272, E501 mortarGeo = tuple(s.reshape((nGeo+1, nGeo+1), order='F') for s in mortarNodes) # noqa: E271, E272 # Interpolate big mortar side to small mortar sides @@ -197,7 +197,7 @@ def RebuildMortarGeometry() -> None: mortarSides = tuple(sides[sides[side.sideID+i].connection] for i in range(1, 3)) mortarElems = tuple(elems[s.elemID] for s in mortarSides) # noqa: E272 - mortarNodes = tuple(e.nodes[sidetovol2(nGeo, s.flip, s.face, elemType)] for e, s in zip(mortarElems, mortarSides)) # noqa: E271, E272 + mortarNodes = tuple(e.nodes[sidetovol2(nGeo, s.flip, s.face, elemType)] for e, s in zip(mortarElems, mortarSides, strict=True)) # noqa: E271, E272, E501 mortarGeo = tuple(s.reshape((nGeo+1, nGeo+1), order='F') for s in mortarNodes) # noqa: E271, E272 # Interpolate big mortar side to small mortar sides diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index af8ca649..8b55580d 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -231,7 +231,7 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: # Deferr update for new boundary faces # > Instead of updating csets_old repeatedly, we collect deferred updates newBCFaces = [] # List of tuples: (new_face_key, combined_name) - for oldFace, subFaces in zip(oldFaces, newFaces): + for oldFace, subFaces in zip(oldFaces, newFaces, strict=True): # Use the inverted index to get candidate face keys that might contain oldFace candidate_sets = [nodeToFace[node] for node in oldFace if node in nodeToFace] if not candidate_sets: diff --git a/pyhope/meshio/meshio_convert.py b/pyhope/meshio/meshio_convert.py index 71ec6d37..8810bb34 100644 --- a/pyhope/meshio/meshio_convert.py +++ b/pyhope/meshio/meshio_convert.py @@ -71,7 +71,7 @@ def gmsh_to_meshio(gmsh) -> meshio.Mesh: # Extract cells elem_types, elem_tags, node_tags = gmsh.model.mesh.getElements() cells = [] - for elemType, elemTags, nodeTags in zip(elem_types, elem_tags, node_tags): + for elemType, elemTags, nodeTags in zip(elem_types, elem_tags, node_tags, strict=True): # `elementName', `dim', `order', `numNodes', `localNodeCoord', `numPrimaryNodes' num_nodes_per_cell = gmsh.model.mesh.getElementProperties(elemType)[3] @@ -86,7 +86,7 @@ def gmsh_to_meshio(gmsh) -> meshio.Mesh: for dim, tag in gmsh.model.getPhysicalGroups(): # Get offset of the node tags (gmsh sorts elements of all dims in succeeding order of node tags, but order of dims might differ) # noqa: E501 elem_types, elem_tags, _ = gmsh.model.mesh.getElements(dim=dim) - elem_tags_group = {meshio.gmsh.gmsh_to_meshio_type[j]: i for i, j in zip(elem_tags, elem_types)} + elem_tags_group = {meshio.gmsh.gmsh_to_meshio_type[j]: i for i, j in zip(elem_tags, elem_types, strict=True)} name = gmsh.model.getPhysicalName(dim, tag) cell_sets[name] = [[] for _ in range(len(cells))] @@ -103,7 +103,7 @@ def gmsh_to_meshio(gmsh) -> meshio.Mesh: idx.append(k) offset = {meshio_cell_type[j]: np.where(elem_tags_group[meshio_cell_type[j]] == elem_tags[j][0])[0] for j in range(len(idx))} # noqa: E501 - elem_tags = [offset[j] + np.int64(i - i[0]) for j, i in zip(meshio_cell_type, elem_tags)] + elem_tags = [offset[j] + np.int64(i - i[0]) for j, i in zip(meshio_cell_type, elem_tags, strict=True)] for j, i in enumerate(idx): cell_sets[name][i].append(elem_tags[j]) @@ -251,12 +251,12 @@ def meshio_to_gmsh(mesh: meshio.Mesh) -> meshio.Mesh: dim_tags[:, 1] = int(geom_tag[0][0]) # Set representatives for ALL 3D entities - for tag, node_used in zip(geom_tag[0], geom_nodes[0]): + for tag, node_used in zip(geom_tag[0], geom_nodes[0], strict=True): dim_tags[int(node_used), 0] = 3 dim_tags[int(node_used), 1] = int(tag) # Set representatives for ALL 2D entities - for tag, node_used in zip(geom_tag[1], geom_nodes[1]): + for tag, node_used in zip(geom_tag[1], geom_nodes[1], strict=True): dim_tags[int(node_used), 0] = 2 dim_tags[int(node_used), 1] = int(tag) From 99b275528839d1859cb4854316bd2e11876df3f9 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:10:23 +0100 Subject: [PATCH 41/59] Linting: Fix raise-without-from-inside-except (B904) --- pyhope/common/common_vars.py | 6 +++--- pyhope/mesh/reader/reader_gambit.py | 4 ++-- pyhope/mesh/reader/reader_hopr.py | 4 ++-- pyhope/mesh/sort/sort_hilbert.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyhope/common/common_vars.py b/pyhope/common/common_vars.py index 7f9105f5..a0e6dc1a 100644 --- a/pyhope/common/common_vars.py +++ b/pyhope/common/common_vars.py @@ -83,15 +83,15 @@ def __version__(self) -> Version: package = pathlib.Path(__file__).parent.parent.name version = importlib.metadata.version(package) # Fallback to pyproject.toml - except importlib.metadata.PackageNotFoundError: + except importlib.metadata.PackageNotFoundError as e: pyproject = pathlib.Path(__file__).parent.parent.parent / 'pyproject.toml' if not pyproject.exists(): - raise FileNotFoundError(f'pyproject.toml not found at {pyproject}') + raise FileNotFoundError(f'pyproject.toml not found at {pyproject}') from e with pyproject.open('r') as p: match = re.search(r'version\s*=\s*["\'](.+?)["\']', p.read()) if not match: - raise ValueError('Version not found in pyproject.toml') + raise ValueError('Version not found in pyproject.toml') from e # noqa: E272 version = match.group(1) return Version(version) diff --git a/pyhope/mesh/reader/reader_gambit.py b/pyhope/mesh/reader/reader_gambit.py index ea9ce1f1..0d0812f6 100644 --- a/pyhope/mesh/reader/reader_gambit.py +++ b/pyhope/mesh/reader/reader_gambit.py @@ -100,8 +100,8 @@ def ReadGambit(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: # Read the file content content = f.readlines() useBinary = not any('CONTROL INFO' in line for line in content) - except UnicodeDecodeError: - raise ValueError('Gambit binary files are not implemented yet') + except UnicodeDecodeError as e: + raise ValueError('Gambit binary files are not implemented yet') from e if not useBinary: # Search for the line containing the number of elements diff --git a/pyhope/mesh/reader/reader_hopr.py b/pyhope/mesh/reader/reader_hopr.py index bb47c34f..2dbdfd7c 100644 --- a/pyhope/mesh/reader/reader_hopr.py +++ b/pyhope/mesh/reader/reader_hopr.py @@ -215,8 +215,8 @@ def ReadHOPR(fnames: list, mesh: meshio.Mesh) -> meshio.Mesh: # points = np.append(points, meshNodes, axis=0) # IMPORTANT: We need to extend the list of points, not append to it pointl.extend(meshNodes.tolist()) - except UnboundLocalError: - raise UnboundLocalError('Something went wrong with the change basis') + except UnboundLocalError as e: + raise UnboundLocalError('Something went wrong with the change basis') from e cells.setdefault(elemType, []).append(elemNodes.astype(np.uint64)) diff --git a/pyhope/mesh/sort/sort_hilbert.py b/pyhope/mesh/sort/sort_hilbert.py index 5c97652c..b9e15837 100644 --- a/pyhope/mesh/sort/sort_hilbert.py +++ b/pyhope/mesh/sort/sort_hilbert.py @@ -159,7 +159,7 @@ def _dfp_patched(self, points: Iterable[Iterable[int]], match_type: bool = False try: distances = self._distances_from_points_numpy(points, match_type=match_type) except Exception as e: - raise RuntimeError(f'HilbertCurve.distances_from_points_numpy encountered an unexpected error: {e}') + raise RuntimeError('HilbertCurve.distances_from_points_numpy encountered an unexpected error') from e # Fallback to original behavior on any unexpected issue # distances = _orig_dfp(self, points, match_type=match_type) else: From ceb7fb43cb03ad7cf484d5e98a0238bae444c900 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:14:17 +0100 Subject: [PATCH 42/59] Linting: Fix unused-loop-control-variable (B007) --- pyhope/mesh/extrude/mesh_extrude.py | 2 +- pyhope/mesh/fem/fem.py | 2 +- pyhope/mesh/mesh_builtin.py | 2 +- pyhope/mesh/topology/mesh_serendipity.py | 2 +- pyproject.toml | 18 +++++++++++++++++- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index f09c0a6c..f2510c1b 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -173,7 +173,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: nodeToFace[node].add(subFace) # We need to unwrap meshcells for each zone, i.e. each 2D boundary condition - for iElem, meshcell in enumerate(meshcells): + for meshcell in meshcells: _ , mdict = meshcell # Iterate over all cell types in this BC diff --git a/pyhope/mesh/fem/fem.py b/pyhope/mesh/fem/fem.py index 2c81b3bc..6ff07d7c 100644 --- a/pyhope/mesh/fem/fem.py +++ b/pyhope/mesh/fem/fem.py @@ -286,7 +286,7 @@ def FEMConnect() -> None: FEMEdgeMapping = {key: i for i, key in enumerate(sorted(edgeKeySet))} # Build the vertex connectivity - for elemID, elem in enumerate(elems): + for elem in elems: elemNodes = cast(np.ndarray, elem.nodes)[:cast(int, elem.type) % 10] vertexInfo: dict[int, tuple[int, tuple[int, ...]]] = {} for locNode in range(len(elemNodes)): diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index 6bce3639..1537198c 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -281,7 +281,7 @@ def MeshCartesian() -> meshio.Mesh: mesh_vars.bcs = [BC() for _ in range(nBCs)] bcs = mesh_vars.bcs - for iBC, bc in enumerate(bcs): + for iBC in range(len(bcs)): # bcs[iBC].update(name = GetStr( 'BoundaryName', number=iBC), # noqa: E251 # bcid = iBC + 1, # noqa: E251 # type = GetIntArray('BoundaryType', number=iBC)) # noqa: E251 diff --git a/pyhope/mesh/topology/mesh_serendipity.py b/pyhope/mesh/topology/mesh_serendipity.py index f3a395b2..535c39f5 100644 --- a/pyhope/mesh/topology/mesh_serendipity.py +++ b/pyhope/mesh/topology/mesh_serendipity.py @@ -112,7 +112,7 @@ def convertSerendipityToFullLagrange(mesh: meshio.Mesh) -> meshio.Mesh: # Loop over all hexahedrons for iElem, elem in enumerate(cdata): # Create the 6 face mid-points - for iFace, face in enumerate(faces): + for iFace in range(len(faces)): center = np.dot(N[iFace], mesh.points[elem]) points[nPoints_old + iFace, :] = center diff --git a/pyproject.toml b/pyproject.toml index 3690a761..a22598df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -160,7 +160,23 @@ exclude = [ target-version = "py310" [tool.ruff.lint] -select = ["E4", "E7", "E9", "F"] +extend-select = [ + "B", # flake8-bugbear + ] +ignore = [ + "EXE001", # shebang-not-executable - we use shebang as file format identifier + "I001", # unsorted-imports - we use logical sorting instead of alphabetical + "RET501", # unnecessary-return-none - we want to be explicit about our return values + "RUF100", # unused-noqa - we want to have multiple linters, thus sometimes more exceptions are necessary + "UP009", # utf8-encoding-declaration - we want to be explicit about our encoding + "UP007", # non-pep604-annotation-union - we want explicit typing.Union annotations + "UP045", # non-pep604-annotation-optional - we want explicit typing.Optional annotations + "PLR0402", # manual-from-import - we want every import specify the module name + # TODO: These should be fixed eventually + "BLE001", # blind-except - narrow errors and exceptions + "S110", # try-except-pass - implement feature.logger branch + "S112", # try-except-continue - implement feature.logger branch + ] [tool.ruff.format] quote-style = "single" From bfb747397304832761e0a8175e0ff9ed0c14c8e6 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:17:11 +0100 Subject: [PATCH 43/59] Linting: Fix loop-iterator-mutation (B909) --- pyhope/mesh/transform/templates/convtest.py | 28 +++++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/pyhope/mesh/transform/templates/convtest.py b/pyhope/mesh/transform/templates/convtest.py index 3eb2bbbf..3e0ea6ad 100644 --- a/pyhope/mesh/transform/templates/convtest.py +++ b/pyhope/mesh/transform/templates/convtest.py @@ -26,6 +26,7 @@ # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- from __future__ import annotations +from typing import Final # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- @@ -50,16 +51,21 @@ def PostDeform(points: npt.NDArray) -> npt.NDArray: # pragma: no cover PyHOPE expects this function to return the deformed points as an np.ndarray. Thus, the function signature remain unchanged. """ - eps = 1./16 - for iPoint, xPoint in enumerate(points): - points[iPoint, 0] = xPoint[0] + eps * np.cos( np.pi*(xPoint[0]-0.5))* \ - np.sin(4*np.pi*(xPoint[1]-0.5))* \ - np.cos( np.pi*(xPoint[2]-0.5)) - points[iPoint, 1] = xPoint[1] + eps * np.cos(3*np.pi*(xPoint[0]-0.5))* \ - np.cos( np.pi*(xPoint[1]-0.5))* \ - np.cos( np.pi*(xPoint[2]-0.5)) - points[iPoint, 2] = xPoint[2] + eps * np.cos( np.pi*(xPoint[0]-0.5))* \ - np.cos(2*np.pi*(xPoint[1]-0.5))* \ - np.cos( np.pi*(xPoint[2]-0.5)) + eps: Final[float] = 1./16 + + nTotal = points.shape[0] + X_out = np.zeros_like(points, dtype=np.float64) + + for i in range(nTotal): + x = points[i, :] + X_out[i, 0] = x[0] + eps * np.cos( np.pi*(x[0]-0.5))* \ + np.sin(4*np.pi*(x[1]-0.5))* \ + np.cos( np.pi*(x[2]-0.5)) + X_out[i, 1] = x[1] + eps * np.cos(3*np.pi*(x[0]-0.5))* \ + np.cos( np.pi*(x[1]-0.5))* \ + np.cos( np.pi*(x[2]-0.5)) + X_out[i, 2] = x[2] + eps * np.cos( np.pi*(x[0]-0.5))* \ + np.cos(2*np.pi*(x[1]-0.5))* \ + np.cos( np.pi*(x[2]-0.5)) return points From 17a1243d2dff67ca0722a1f8e46ae5a479a48938 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:21:18 +0100 Subject: [PATCH 44/59] Linting: Fix if-else-block-instead-of-if-exp (SIM108) --- pyhope/common/common_tools.py | 8 ++------ pyhope/output/output.py | 5 +---- pyhope/readintools/commandline.py | 5 +---- pyhope/readintools/readintools.py | 8 ++------ 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/pyhope/common/common_tools.py b/pyhope/common/common_tools.py index 508725e0..1afb18e4 100644 --- a/pyhope/common/common_tools.py +++ b/pyhope/common/common_tools.py @@ -132,12 +132,8 @@ def add(self, index: int, values) -> None: def remove_index(self, indices) -> None: """ Remove the sublist at idx and remove the integer idx from all remaining sublists """ - if isinstance(indices, int): - # Convert to a set for fast operations - indices = {indices} - else: - # Convert list to set for O(1) lookups - indices = set(indices) + # Convert to a set for fast operations + indices = {indices} if isinstance(indices, int) else set(indices) # Create a set to hold all affected keys affected_keys = set() diff --git a/pyhope/output/output.py b/pyhope/output/output.py index 73a0db31..c8998712 100644 --- a/pyhope/output/output.py +++ b/pyhope/output/output.py @@ -216,10 +216,7 @@ def printoption(option: str, value: str, status: str, length: int = 31) -> None: length (int): (Optional.) Number of characters in each line """ try: - if len(value) > length: - pvalue = f'{value[:(length-3)]}...' - else: - pvalue = value + pvalue = f'{value[:length - 3]}...' if len(value) > length else value except TypeError: pvalue = value print(f'│ {option:>{length}} │ {pvalue:<{length}} │ {status} │') diff --git a/pyhope/readintools/commandline.py b/pyhope/readintools/commandline.py index 13bbb450..0c2ff707 100644 --- a/pyhope/readintools/commandline.py +++ b/pyhope/readintools/commandline.py @@ -95,10 +95,7 @@ def __init__(self, argv, name: str, version: str, commit: Optional[str]) -> None if isinstance(default, bool): default = 'T' if default else 'F' - if config.prms[key]['help']: - help = config.prms[key]['help'] - else: - help = '' + help = config.prms[key]['help'] if config.prms[key]['help'] else '' self.helpjoin(f'{key:<{PAR_LENGTH}} = {default:>{DEF_LENGTH}} ! {help}') diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 0023d77b..441d7b7e 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -95,10 +95,7 @@ def strToFloatOrPi(helpstr: str) -> float: match len(splitstr): # Determine prefactor of pi, interpreting empty string as one case 2: - if splitstr[0]: - value = float(splitstr[0])*np.pi - else: - value = np.pi + value = float(splitstr[0]) * np.pi if splitstr[0] else np.pi # No 'pi' found in splitstr, parse as float case 1: @@ -339,8 +336,7 @@ def GetParam(name : str, if config.params.has_option('general', name): if config.prms[name]['multiple']: # We can request specific indices - if number is None: num = config.prms[name]['counter']-1 # noqa: E701 - else: num = number # noqa: E701 + num = config.prms[name]['counter'] - 1 if number is None else number input = [s for s in config.params.get('general', name).split('\n') if s != ''] if num >= len(input): From 28872f075a9d69f93a72d81823702e4c3893e552 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:21:23 +0100 Subject: [PATCH 45/59] Linting: Fix dict-get-with-none-default (SIM910) --- pyhope/mesh/extrude/mesh_extrude.py | 2 +- pyhope/mesh/topology/mesh_splittohex.py | 2 +- pyhope/mesh/topology/mesh_topology.py | 2 +- pyhope/mesh/transform/mesh_transform.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index f2510c1b..707916e4 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -184,7 +184,7 @@ def MeshExtrude(mesh: meshio.Mesh) -> meshio.Mesh: # Set up the extrusion function extrude, faces = elemExtruder.get(mtype[:4], (None, None)) elemNum = ho_key + (8 if cast(str, mtype).startswith('quad') else 6) - faceMap = faceMaper.get(elemNum, None) + faceMap = faceMaper.get(elemNum) # Consistency checks if faceMap is None: diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 8b55580d..967af78f 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -282,7 +282,7 @@ def MeshSplitToHex(mesh: meshio.Mesh) -> meshio.Mesh: # Add back the existing quad boundary faces attached to carried-over hexahedra if not splitToHexZ and hexBCQuads: for qset in hexBCQuads: - qnodes = hexBCSet.get(qset, None) + qnodes = hexBCSet.get(qset) if qnodes is None: continue diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 1126cfd2..61583af9 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -186,7 +186,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: elemName = elemNames[iElem] split, faces = elemSplitter.get(elemType, (None, None)) - faceMap = faceMaper.get(elemType, None) + faceMap = faceMaper.get(elemType) # Sanity check if faceMap is None: diff --git a/pyhope/mesh/transform/mesh_transform.py b/pyhope/mesh/transform/mesh_transform.py index 8fd8d166..e056f2da 100644 --- a/pyhope/mesh/transform/mesh_transform.py +++ b/pyhope/mesh/transform/mesh_transform.py @@ -65,7 +65,7 @@ def CalcStretching(nZones: int, zone: int, nElems: npt.NDArray, lEdges: npt.NDAr (nZones, nZones): 'combination' # Stretched element arrangement with a combination of l0 and factor } - stretchingType = conditions.get((nl0, nFactor), None) + stretchingType = conditions.get((nl0, nFactor)) if stretchingType == 'combination': print(hopout.warn('Both l0 and a stretching factor are provided. ' + From d2560d6420550b871e12860feaef4bcb8364115d Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:24:08 +0100 Subject: [PATCH 46/59] Linting: Fix superfluous-else-return (RET505) --- pyhope/basis/basis_jacobian.py | 5 +- pyhope/mesh/connect/connect_mortar.py | 9 ++- pyhope/mesh/mesh_common.py | 83 ++++++++++++------------- pyhope/mesh/mesh_mortar.py | 3 +- pyhope/mesh/topology/mesh_splittohex.py | 62 +++++++++--------- pyhope/readintools/readintools.py | 5 +- 6 files changed, 79 insertions(+), 88 deletions(-) diff --git a/pyhope/basis/basis_jacobian.py b/pyhope/basis/basis_jacobian.py index b3cf320d..cce1aeda 100644 --- a/pyhope/basis/basis_jacobian.py +++ b/pyhope/basis/basis_jacobian.py @@ -52,10 +52,9 @@ def evaluate_jacobian_dispatch(nodeCoords, VdmGLtoAP, D_EqToGL, elem_type): if elem_type in SIMPLEX_TYPES: return evaluate_jacobian_simplex(nodeCoords, VdmGLtoAP, D_EqToGL) - elif elem_type == HEX_TYPE: + if elem_type == HEX_TYPE: return evaluate_jacobian( nodeCoords, VdmGLtoAP, D_EqToGL) - else: - raise ValueError(f"Unsupported element type {elem_type}") + raise ValueError(f"Unsupported element type {elem_type}") def plot_histogram(data: npt.NDArray[np.float64]) -> None: diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index 33360981..5a5a0361 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -489,7 +489,7 @@ def find_mortar_match( targetCorners: npt.NDArray # We only allow 2-1 matches, so in the end we should have exactly 1 match if len(matchEdges) > 1: return False - elif len(matchEdges) == 1: + if len(matchEdges) == 1: matches.append((targetEdge, matchEdges.pop())) if len(matches) != 2: @@ -531,7 +531,7 @@ def find_mortar_match( targetCorners: npt.NDArray # This should result in exactly 1 match if len(matchEdges) > 1: return False - elif len(matchEdges) == 1: + if len(matchEdges) == 1: matches.append((targetEdge, matchEdges.pop())) if len(matches) != 4: @@ -591,7 +591,7 @@ def calculate_area(corners: npt.NDArray[np.float64]) -> float: if n == 3: # Triangle # noqa: E271 return 0.5 * norm(np.cross(p[1]-p[0], p[2]-p[0])) # noqa: E271 - elif n == 4: # Quadrilateral + if n == 4: # Quadrilateral # Diagonal split 1: (0,1,2) + (0,2,3) area1 = 0.5 * norm(np.cross(p[1]-p[0], p[2]-p[0])) # noqa: E271 area1 += 0.5 * norm(np.cross(p[2]-p[0], p[3]-p[0])) # noqa: E271 @@ -602,8 +602,7 @@ def calculate_area(corners: npt.NDArray[np.float64]) -> float: # For bilinear quads, average both diagonal triangulations return (area1 + area2) / 2 - else: - raise IndexError('Invalid number of side corners') + raise IndexError('Invalid number of side corners') # INFO: Uncached version diff --git a/pyhope/mesh/mesh_common.py b/pyhope/mesh/mesh_common.py index 4af36f54..c08ce4fe 100644 --- a/pyhope/mesh/mesh_common.py +++ b/pyhope/mesh/mesh_common.py @@ -320,52 +320,49 @@ def FaceOrdering(side_type: str, order: int, dtype=np.int32) -> npt.NDArray: # Total nodes on face: (nGeo+1)**2 if order == 1: return np.arange(4, dtype=dtype) - else: - n = order - grid = np.arange((n+1)**2).reshape(n+1, n+1) - # Corners: bottom-left, bottom-right, top-right, top-left - corners = np.array((grid[0, 0], grid[0, n], grid[n, n], grid[n, 0])) - # Bottom edge (excluding corners): row 0, columns 1 to n-1 (left-to-right) - bottom_edge = grid[0, 1:n] - # Right edge: column n, rows 1 to n-1 (bottom-to-top) - right_edge = grid[1:n, n] - # Top edge: row n, columns n-1 to 1 (right-to-left) - top_edge = grid[n, n-1:0:-1] - # Left edge: column 0, rows n-1 to 1 (top-to-bottom) - left_edge = grid[n-1:0:-1, 0] - # Interior nodes: remaining nodes in row-major order - interior = grid[1:n, 1:n].flatten() - # Assemble ordering: corners, edges, interior - # ordering = np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior)) - return np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior), dtype=dtype) - - elif side_type.lower() == 'triangle': + n = order + grid = np.arange((n+1)**2).reshape(n+1, n+1) + # Corners: bottom-left, bottom-right, top-right, top-left + corners = np.array((grid[0, 0], grid[0, n], grid[n, n], grid[n, 0])) + # Bottom edge (excluding corners): row 0, columns 1 to n-1 (left-to-right) + bottom_edge = grid[0, 1:n] + # Right edge: column n, rows 1 to n-1 (bottom-to-top) + right_edge = grid[1:n, n] + # Top edge: row n, columns n-1 to 1 (right-to-left) + top_edge = grid[n, n-1:0:-1] + # Left edge: column 0, rows n-1 to 1 (top-to-bottom) + left_edge = grid[n-1:0:-1, 0] + # Interior nodes: remaining nodes in row-major order + interior = grid[1:n, 1:n].flatten() + # Assemble ordering: corners, edges, interior + # ordering = np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior)) + return np.concatenate((corners, bottom_edge, right_edge, top_edge, left_edge, interior), dtype=dtype) + + if side_type.lower() == 'triangle': # Total nodes on face: (nGeo+1)*(nGeo+2)//2 if order == 1: return np.arange(3, dtype=dtype) - else: - p = order - # Build the tensor ordering as a list of (i, j) for which i+j <= p. - nodes = [] - for i in range(p+1): - nodes.extend((i, j) for j in range(p+1 - i)) - # Define vertices in the reference triangle: - vertices = [(0, 0), (p, 0), (0, p)] - # Edge from vertex0 (0,0) to vertex1 (p,0): nodes with j==0 (excluding vertices) - edge01 = [(i, 0) for i in range(1, p)] - # Edge from vertex1 (p,0) to vertex2 (0,p): nodes on the line i+j==p (excluding vertices) - edge12 = [(i, p-i) for i in range(p-1, 0, -1)] - # Edge from vertex2 (0,p) to vertex0 (0,0): nodes with i==0 (excluding vertices) - edge20 = [(0, j) for j in range(1, p)] - # Interior nodes: those not on the boundary - boundary = set(vertices + edge01 + edge12 + edge20) - interior = [node for node in nodes if node not in boundary] - # Assemble ordering: vertices, then edge nodes in order, then interior nodes. - desired = vertices + edge01 + edge12 + edge20 + interior - ordering = [nodes.index(nd) for nd in desired] - return np.array(ordering, dtype=dtype) - else: - raise ValueError(f'Unsupported side type: {side_type}') + p = order + # Build the tensor ordering as a list of (i, j) for which i+j <= p. + nodes = [] + for i in range(p+1): + nodes.extend((i, j) for j in range(p+1 - i)) + # Define vertices in the reference triangle: + vertices = [(0, 0), (p, 0), (0, p)] + # Edge from vertex0 (0,0) to vertex1 (p,0): nodes with j==0 (excluding vertices) + edge01 = [(i, 0) for i in range(1, p)] + # Edge from vertex1 (p,0) to vertex2 (0,p): nodes on the line i+j==p (excluding vertices) + edge12 = [(i, p-i) for i in range(p-1, 0, -1)] + # Edge from vertex2 (0,p) to vertex0 (0,0): nodes with i==0 (excluding vertices) + edge20 = [(0, j) for j in range(1, p)] + # Interior nodes: those not on the boundary + boundary = set(vertices + edge01 + edge12 + edge20) + interior = [node for node in nodes if node not in boundary] + # Assemble ordering: vertices, then edge nodes in order, then interior nodes. + desired = vertices + edge01 + edge12 + edge20 + interior + ordering = [nodes.index(nd) for nd in desired] + return np.array(ordering, dtype=dtype) + raise ValueError(f'Unsupported side type: {side_type}') @cache diff --git a/pyhope/mesh/mesh_mortar.py b/pyhope/mesh/mesh_mortar.py index c0596e79..2fd5e4e7 100644 --- a/pyhope/mesh/mesh_mortar.py +++ b/pyhope/mesh/mesh_mortar.py @@ -70,8 +70,7 @@ def RebuildMortarGeometry() -> None: case Policy.auto .value: if not hasattr(mesh_vars, 'hasMortarsInterzone') or not mesh_vars.hasMortarsInterzone: return None - else: - pass + pass case Policy.always.value: pass diff --git a/pyhope/mesh/topology/mesh_splittohex.py b/pyhope/mesh/topology/mesh_splittohex.py index 967af78f..34d0a56b 100644 --- a/pyhope/mesh/topology/mesh_splittohex.py +++ b/pyhope/mesh/topology/mesh_splittohex.py @@ -434,29 +434,28 @@ def prism_to_hex_points(order: int, z_split: bool = False) -> tuple[npt.NDArray, np.array(( 0, 1, 2), dtype=int), # index 12 np.array(( 3, 4, 5), dtype=int), # index 13 ) - else: - # z_split: add vertical mid-edges + inside node - return ( # Nodes on edges - np.array(( 0, 1 ), dtype=int), # index 6 - np.array(( 1, 2 ), dtype=int), # index 7 - np.array(( 0, 2 ), dtype=int), # index 8 - np.array(( 3, 4 ), dtype=int), # index 9 - np.array(( 4, 5 ), dtype=int), # index 10 - np.array(( 3, 5 ), dtype=int), # index 11 - # Nodes on faces - np.array(( 0, 1, 2), dtype=int), # index 12 - np.array(( 3, 4, 5), dtype=int), # index 13 - # Nodes on vertical edges - np.array(( 0, 3 ), dtype=int), # index 14 - np.array(( 1, 4 ), dtype=int), # index 15 - np.array(( 2, 5 ), dtype=int), # index 16 - # Inside node - np.arange( 0, 6 , dtype=int), # index 17 - # Nodes on rectangular face centers - np.array(( 0, 1, 3, 4), dtype=int), # index 18 - np.array(( 1, 2, 4, 5), dtype=int), # index 19 - np.array(( 0, 2, 3, 5), dtype=int), # index 20 - ) + # z_split: add vertical mid-edges + inside node + return ( # Nodes on edges + np.array(( 0, 1 ), dtype=int), # index 6 + np.array(( 1, 2 ), dtype=int), # index 7 + np.array(( 0, 2 ), dtype=int), # index 8 + np.array(( 3, 4 ), dtype=int), # index 9 + np.array(( 4, 5 ), dtype=int), # index 10 + np.array(( 3, 5 ), dtype=int), # index 11 + # Nodes on faces + np.array(( 0, 1, 2), dtype=int), # index 12 + np.array(( 3, 4, 5), dtype=int), # index 13 + # Nodes on vertical edges + np.array(( 0, 3 ), dtype=int), # index 14 + np.array(( 1, 4 ), dtype=int), # index 15 + np.array(( 2, 5 ), dtype=int), # index 16 + # Inside node + np.arange( 0, 6 , dtype=int), # index 17 + # Nodes on rectangular face centers + np.array(( 0, 1, 3, 4), dtype=int), # index 18 + np.array(( 1, 2, 4, 5), dtype=int), # index 19 + np.array(( 0, 2, 3, 5), dtype=int), # index 20 + ) case _: import pyhope.output.output as hopout hopout.error(f'Order {order} not supported for element splitting') @@ -535,17 +534,16 @@ def prism_to_hex_split(z_split: bool = False) -> tuple[npt.NDArray, ...]: np.array(( 1, 7, 12, 6, 4, 10, 13, 9), dtype=int), np.array(( 2, 8, 12, 7, 5, 11, 13, 10), dtype=int), ) - else: - # z_split: split each of the 3 base hexahedra into two stacked hexahedra - return (np.array(( 0, 6, 12, 8, 14, 18, 17, 20), dtype=int), - np.array(( 14, 18, 17, 20, 3, 9, 13, 11), dtype=int), + # z_split: split each of the 3 base hexahedra into two stacked hexahedra + return (np.array(( 0, 6, 12, 8, 14, 18, 17, 20), dtype=int), + np.array(( 14, 18, 17, 20, 3, 9, 13, 11), dtype=int), - np.array(( 1, 7, 12, 6, 15, 19, 17, 18), dtype=int), - np.array(( 15, 19, 17, 18, 4, 10, 13, 9), dtype=int), + np.array(( 1, 7, 12, 6, 15, 19, 17, 18), dtype=int), + np.array(( 15, 19, 17, 18, 4, 10, 13, 9), dtype=int), - np.array(( 2, 8, 12, 7, 16, 20, 17, 19), dtype=int), - np.array(( 16, 20, 17, 19, 5, 11, 13, 10), dtype=int), - ) + np.array(( 2, 8, 12, 7, 16, 20, 17, 19), dtype=int), + np.array(( 16, 20, 17, 19, 5, 11, 13, 10), dtype=int), + ) @cache diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 441d7b7e..d6f61f06 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -80,10 +80,9 @@ def strToBool(val: Union[int, bool, str]) -> bool: # From distutils.util.strtob if val in ('y', 'yes', 't', 'true' , 'on' , '1'): # noqa: E271 return True - elif val in ('n', 'no' , 'f', 'false', 'off', '0'): # noqa: E271 + if val in ('n', 'no' , 'f', 'false', 'off', '0'): # noqa: E271 return False - else: - raise ValueError(f'invalid truth value {val!r}') + raise ValueError(f'invalid truth value {val!r}') def strToFloatOrPi(helpstr: str) -> float: From 0ea3100db6d216b235874267898448acffd03523 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:24:31 +0100 Subject: [PATCH 47/59] Linting: Fix superfluous-else-continue (RET507) --- pyhope/basis/basis_connect.py | 2 +- pyhope/basis/basis_watertight.py | 4 ++-- pyhope/check/check_install.py | 5 ++--- pyhope/mesh/topology/mesh_serendipity.py | 2 +- pyhope/mesh/transform/mesh_transform.py | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pyhope/basis/basis_connect.py b/pyhope/basis/basis_connect.py index 67e8c0b2..e228f431 100644 --- a/pyhope/basis/basis_connect.py +++ b/pyhope/basis/basis_connect.py @@ -192,7 +192,7 @@ def CheckConnect() -> None: if side.connection is None or side.sideType < 0: continue # Big mortar side is counted once - elif side.connection < 0: + if side.connection < 0: nconn += 1 # Internal side: only count the canonical representative and ignore virtual mortar sides elif side.connection >= 0: diff --git a/pyhope/basis/basis_watertight.py b/pyhope/basis/basis_watertight.py index 0c421fcb..428de1d6 100644 --- a/pyhope/basis/basis_watertight.py +++ b/pyhope/basis/basis_watertight.py @@ -151,7 +151,7 @@ def check_sides(elem, continue # Big mortar side - elif side.connection < 0: + if side.connection < 0: mortarType = abs(side.connection) # INFO: This should be faster but I could not confirm the speedup in practice # nSurf = eval_nsurf(np.moveaxis( points[ nodes], 2, 0), VdmEqToGP, DGP, weights) @@ -323,7 +323,7 @@ def CheckWatertight() -> None: if side.connection is None or side.sideType < 0: continue # Big mortar side is counted once - elif side.connection < 0: + if side.connection < 0: nconn += 1 # Internal side: only count the canonical representative and ignore virtual mortar sides elif side.connection >= 0: diff --git a/pyhope/check/check_install.py b/pyhope/check/check_install.py index ebce3d9f..b509c2ff 100644 --- a/pyhope/check/check_install.py +++ b/pyhope/check/check_install.py @@ -102,9 +102,8 @@ def _make_request(url : str, bar.title( '│ Downloading tests') # Retry the request continue - else: - # Re-raise other HTTP errors - raise + # Re-raise other HTTP errors + raise apiURL = f'https://api.github.com/repos/{user}/{repo}/contents/{path}?ref={branch}' diff --git a/pyhope/mesh/topology/mesh_serendipity.py b/pyhope/mesh/topology/mesh_serendipity.py index 535c39f5..adc431b4 100644 --- a/pyhope/mesh/topology/mesh_serendipity.py +++ b/pyhope/mesh/topology/mesh_serendipity.py @@ -176,7 +176,7 @@ def convertSerendipityToFullLagrange(mesh: meshio.Mesh) -> meshio.Mesh: if 'z' in face: continue # 2nd order quadrilaterial faces - elif len(faceNodes[iFace]) == 8: + if len(faceNodes[iFace]) == 8: # Here, we are on the quads and not the actual element center = np.dot(N[iFace], mesh.points[elem[faceNodes[iFace]]]) points[nPoints_old + iFace, :] = center diff --git a/pyhope/mesh/transform/mesh_transform.py b/pyhope/mesh/transform/mesh_transform.py index e056f2da..879d2b06 100644 --- a/pyhope/mesh/transform/mesh_transform.py +++ b/pyhope/mesh/transform/mesh_transform.py @@ -112,7 +112,7 @@ def CalcStretching(nZones: int, zone: int, nElems: npt.NDArray, lEdges: npt.NDAr if nElems[iDim] == 1 or dx[iDim] == 0: progFac[iDim] = 1. continue - elif nElems[iDim] == 2: + if nElems[iDim] == 2: progFac[iDim] = dx[iDim] - 1. continue From a36e7854cf69682774ce66eb80695b919ae86512 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:26:57 +0100 Subject: [PATCH 48/59] Linting: Fix unnecessary-placeholder (PIE790) --- pyhope/mesh/mesh_mortar.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyhope/mesh/mesh_mortar.py b/pyhope/mesh/mesh_mortar.py index 2fd5e4e7..c81e472a 100644 --- a/pyhope/mesh/mesh_mortar.py +++ b/pyhope/mesh/mesh_mortar.py @@ -70,7 +70,6 @@ def RebuildMortarGeometry() -> None: case Policy.auto .value: if not hasattr(mesh_vars, 'hasMortarsInterzone') or not mesh_vars.hasMortarsInterzone: return None - pass case Policy.always.value: pass From 532c656366b97163ef32096c2a9793db1fa07983 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:31:19 +0100 Subject: [PATCH 49/59] Linting: Fix repeated-append (FURB113) --- pyhope/readintools/readintools.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index d6f61f06..7e0f2a77 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -697,13 +697,11 @@ def __enter__(self) -> ConfigParser: BCType = cast(h5py.Dataset, f['BCType'])[:] # Write geometric order info to file - mesh_params.append(f'NGeo = {NGeo}') - mesh_params.append(f'MeshIsAlreadyCurved = {"T" if NGeo > 1 else "F"}') + mesh_params.extend((f'NGeo = {NGeo}', f'MeshIsAlreadyCurved = {"T" if NGeo > 1 else "F"}')) # Setup boundary conditions for iBC, BC in enumerate(BCNames): - mesh_params.append(f'BoundaryName = {BC}') - mesh_params.append(f'BoundaryType = (/{", ".join(map(str, BCType[iBC]))}/)') + mesh_params.extend((f'BoundaryName = {BC}', f'BoundaryType = (/{", ".join(map(str, BCType[iBC]))}/)')) # Join lines into a single string mesh_param = '\n'.join(mesh_params) From 330301914d5d89a70ef857c77c01347b9d5d8283 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:32:26 +0100 Subject: [PATCH 50/59] Linting: Fix write-whole-file (FURB103) --- pyhope/check/check_install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/check/check_install.py b/pyhope/check/check_install.py index b509c2ff..f3396522 100644 --- a/pyhope/check/check_install.py +++ b/pyhope/check/check_install.py @@ -37,6 +37,7 @@ # ---------------------------------------------------------------------------------------------------------------------------------- import h5py import numpy as np +import pathlib # ---------------------------------------------------------------------------------------------------------------------------------- # Local imports # ---------------------------------------------------------------------------------------------------------------------------------- @@ -144,8 +145,7 @@ def _make_request(url : str, content = lfs_u.read() # Write the final content (either regular file or LFS file) to disk - with open(subPath, 'wb') as f: - f.write(content) + pathlib.Path(subPath).write_bytes(content) case 'dir': # Recursively call the function for subdirectories From 616d2e68c5fb982e678d097013b7594c83d3743f Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:33:07 +0100 Subject: [PATCH 51/59] Linting: Fix for-loop-set-mutations (FURB142) --- pyhope/mesh/fem/fem.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyhope/mesh/fem/fem.py b/pyhope/mesh/fem/fem.py index 6ff07d7c..17345a6b 100644 --- a/pyhope/mesh/fem/fem.py +++ b/pyhope/mesh/fem/fem.py @@ -225,8 +225,7 @@ def FEMConnect() -> None: # Seed edgeSet from the graph keys plus every raw edge base representation edgeSet = set(edgeGraph.keys()) - for _, _, (n0, n1) in edgesRaw: - edgeSet.add((n0, n1) if n0 < n1 else (n1, n0)) + edgeSet.update((n0, n1) if n0 < n1 else (n1, n0) for _, _, (n0, n1) in edgesRaw) for nodeStart in edgeSet: # Done with this node From d517ac0f5310f17711c7b2902283314430cd5710 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:34:32 +0100 Subject: [PATCH 52/59] Linting: Fix unnecessary-enumerate (FURB148) --- pyhope/mesh/mesh_builtin.py | 2 +- pyhope/meshio/meshio_convert.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index 1537198c..bc1d8090 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -239,7 +239,7 @@ def MeshCartesian() -> meshio.Mesh: # Create the surfaces s = [None for _ in range(len(faces(elemType)))] - for index, _ in enumerate(s): + for index in range(len(s)): s[index] = gmsh.model.geo.addPlaneSurface([el[index]], tag=offsets+index+1) # We need to define the surfaces as transfinite surface diff --git a/pyhope/meshio/meshio_convert.py b/pyhope/meshio/meshio_convert.py index 8810bb34..3a77417d 100644 --- a/pyhope/meshio/meshio_convert.py +++ b/pyhope/meshio/meshio_convert.py @@ -196,7 +196,7 @@ def meshio_to_gmsh(mesh: meshio.Mesh) -> meshio.Mesh: # Process each 2D CellBlock: keep shared point indices, set BCs # NOTE: Split by BC id so each physical surface becomes its own entity - for _, cell_block in enumerate(surface_cells): + for cell_block in surface_cells: cell_type = cell_block.type # NOTE: This will assign 0 to faces not found, assuming they are internal faces cellBC = np.asarray([cellTypeToBC[cell_type].get(int(idx), 0) for idx in range(len(cell_block))], dtype=int) From 308bc6f866a01a352803160a6b921246e1415591 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:35:49 +0100 Subject: [PATCH 53/59] Linting: Fix missing-f-string-syntax (RUF027) --- pyhope/mesh/extrude/mesh_extrude.py | 4 ++-- pyhope/meshio/meshio_convert.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyhope/mesh/extrude/mesh_extrude.py b/pyhope/mesh/extrude/mesh_extrude.py index 707916e4..56c5fe82 100644 --- a/pyhope/mesh/extrude/mesh_extrude.py +++ b/pyhope/mesh/extrude/mesh_extrude.py @@ -372,7 +372,7 @@ def extrude_pris(nodes: np.ndarray, # FIXME: Implement the other orders case _: - raise ValueError('Extrusion not implemented for NGeo={order}') + raise ValueError(f'Extrusion not implemented for NGeo={order}') return newNodes, newPoints @@ -436,7 +436,7 @@ def extrude_hexa(nodes: np.ndarray, # FIXME: Implement the other orders case _: - raise ValueError('Extrusion not implemented for NGeo={order}') + raise ValueError(f'Extrusion not implemented for NGeo={order}') return newNodes, newPoints diff --git a/pyhope/meshio/meshio_convert.py b/pyhope/meshio/meshio_convert.py index 3a77417d..9bb6e611 100644 --- a/pyhope/meshio/meshio_convert.py +++ b/pyhope/meshio/meshio_convert.py @@ -163,7 +163,7 @@ def meshio_to_gmsh(mesh: meshio.Mesh) -> meshio.Mesh: if not node_free and node_used in usedNodes: # All candidate nodes already used; fall back to the first (still valid, we just can't make it unique) # hopout.routine(f'Note: reusing representative node {rep_node} for 3D entity tag {tag}') - hopout.error('All candidate nodes already used for 3D entity tag {tag}') + hopout.error(f'All candidate nodes already used for 3D entity tag {tag}') geom_nodes[0].append(node_used) usedNodes.add(node_used) @@ -221,7 +221,7 @@ def meshio_to_gmsh(mesh: meshio.Mesh) -> meshio.Mesh: if not node_free and node_used in usedNodes: # All candidate nodes already used; fall back to the first (still valid, we just can't make it unique) # hopout.routine(f'Note: reusing representative node {rep_node} for 3D entity tag {tag}') - hopout.error('All candidate nodes already used for 3D entity tag {tag}') + hopout.error(f'All candidate nodes already used for 3D entity tag {tag}') geom_nodes[1].append(node_used) usedNodes.add(node_used) From 609ccf71b3606109b6980633bf89ed0b17ff6c10 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:40:21 +0100 Subject: [PATCH 54/59] Linting: Fix collection-literal-concatenation (RUF005) --- pyhope/gmsh/gmsh_install.py | 6 +++--- pyhope/mesh/connect/connect_mortar.py | 4 ++-- pyhope/mesh/topology/mesh_topology.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pyhope/gmsh/gmsh_install.py b/pyhope/gmsh/gmsh_install.py index cb99eb31..a4bbb548 100644 --- a/pyhope/gmsh/gmsh_install.py +++ b/pyhope/gmsh/gmsh_install.py @@ -194,7 +194,7 @@ def PkgsInstallGmsh(system: str, arch: str, version: str) -> None: meta = metadata.metadata('gmsh') if meta is not None: try: - _ = subprocess.run(command + ['uninstall'] + ['gmsh'], check=True) # noqa: E501 + _ = subprocess.run([*command, 'uninstall', 'gmsh'], check=True) # noqa: E501 except subprocess.CalledProcessError: print(hopout.warn( 'Failed to uninstall system Gmsh. Please run the following commands manually:')) print(hopout.warn( '$ python -m pip uninstall gmsh')) @@ -205,7 +205,7 @@ def PkgsInstallGmsh(system: str, arch: str, version: str) -> None: pass # Install the package in the current environment - _ = subprocess.run(command + ['install'] + [pkgs], check=True) + _ = subprocess.run([*command, 'install', pkgs], check=True) else: # Install the package in the current environment - _ = subprocess.run(command + ['install'] + ['gmsh'], check=True) + _ = subprocess.run([*command, 'install', 'gmsh'], check=True) diff --git a/pyhope/mesh/connect/connect_mortar.py b/pyhope/mesh/connect/connect_mortar.py index 5a5a0361..7131d0a4 100644 --- a/pyhope/mesh/connect/connect_mortar.py +++ b/pyhope/mesh/connect/connect_mortar.py @@ -217,7 +217,7 @@ def ConnectMortar( nConnSide : list connect_mortar_sides(sideIDs, elems, rbtsides, offsetManager, bcID) # Remove the target side from the list - indexList.remove_index([targetID] + list(comboIDs)) + indexList.remove_index([targetID, *list(comboIDs)]) # Update the progress bar bar.step(len(nbSideID) + 1) @@ -248,7 +248,7 @@ def ConnectMortar( nConnSide : list connect_mortar_sides(sideIDs, elems, rbtsides, offsetManager, bcID) # Remove the target side from the list - indexList.remove_index([targetID] + list(comboIDs)) + indexList.remove_index([targetID, *list(comboIDs)]) # Update the progress bar bar.step(len(nbSideID) + 1) diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 61583af9..034384f8 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -220,7 +220,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: pointl.append(center.tolist()) # Overwrite the element with the new indices - elem = np.array(list(elem) + [nPoints]) + elem = np.array([*list(elem), nPoints]) nPoints += 1 case 2: # Generate the grid of new points From 7fcea2619997e5993a5a295646f75c776b22cd64 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:46:26 +0100 Subject: [PATCH 55/59] Linting: Fix read-whole-file (FURB101) --- pyhope/readintools/readintools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 7e0f2a77..1af2a45f 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -29,6 +29,7 @@ import os import subprocess import sys +from pathlib import Path from typing import Optional, Union, cast, final from typing_extensions import override # ---------------------------------------------------------------------------------------------------------------------------------- @@ -644,8 +645,7 @@ def __enter__(self) -> ConfigParser: mesh_mode = True else: try: - with open(self.input, 'r', encoding='utf-8') as f: - f.read() + _ = Path(self.input).read_text(encoding='utf-8') parameter_mode = True except UnicodeDecodeError: hopout.error(f'Parameter or mesh file [󰇘]/{os.path.basename(self.input)} are of unknown type') From be5f3a6fc9af70ba816c1444f47f9203a8ddd11d Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:56:12 +0100 Subject: [PATCH 56/59] Linting: Fix if-else-block-instead-of-if-exp (SIM108) --- pyhope/io/io_xdmf.py | 8 ++------ pyhope/readintools/commandline.py | 5 +---- pyhope/readintools/readintools.py | 11 +++-------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/pyhope/io/io_xdmf.py b/pyhope/io/io_xdmf.py index 20e50af7..1c70c854 100644 --- a/pyhope/io/io_xdmf.py +++ b/pyhope/io/io_xdmf.py @@ -82,12 +82,8 @@ def XdmfWriterInit(self, for mesh in meshList: # Assign the correct subgrid name - if mesh.info is not None and 'name' in mesh.info: - gridname = mesh.info['name'] - else: - gridname = 'Grid' - - grid = ET.SubElement(domain, 'Grid', Name=gridname) + gridname = mesh.info['name'] if mesh.info is not None and 'name' in mesh.info else 'Grid' + grid = ET.SubElement(domain, 'Grid', Name=gridname) self.write_points( grid , mesh.points) # self.field_data( mesh.field_data, information) diff --git a/pyhope/readintools/commandline.py b/pyhope/readintools/commandline.py index 0c2ff707..5bc2a262 100644 --- a/pyhope/readintools/commandline.py +++ b/pyhope/readintools/commandline.py @@ -86,10 +86,7 @@ def __init__(self, argv, name: str, version: str, commit: Optional[str]) -> None self.helpjoin(separator()) continue - if config.prms[key]['default'] is not None: - default = config.prms[key]['default'] - else: - default = '' + default = config.prms[key]['default'] if config.prms[key]['default'] is not None else '' # Convert booleans to strings if isinstance(default, bool): diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index 1af2a45f..c39c1cd2 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -442,10 +442,8 @@ def GetRealArray(name: str, default: Optional[str] = None, number: Optional[int] value = value.split('/)')[0] # Commas separate 1st dimension, double commas separate 2nd dimension - if ',,' in value: - value = [s.split(',') for s in value.split(',,')] - else: - value = value.split(',') + value = [s.split(',') for s in value.split(',,')] if ',,' in value else value.split(',') + try: value = np.vectorize(strToFloatOrPi)(value) except ValueError as e: # pragma: no cover @@ -583,10 +581,7 @@ def _read_file(self) -> list: # Replace variables in the parameter file for var, value in variables.items(): # Convert arrays to string format - if isinstance(value, list): - replacement = f'(/{",".join(map(str, value))}/)' - else: - replacement = str(value) + replacement = f'(/{",".join(map(str, value))}/)' if isinstance(value, list) else str(value) # Ensure exact match replacement (avoiding substring issues) if '=' in line: From abdd6ec2c6fe7f606c8aaaadb4c53a238161e634 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 16:59:40 +0100 Subject: [PATCH 57/59] Linting: Fix unnecessary-comprehension (C416) --- pyhope/__init__.py | 8 ++++++-- pyhope/mesh/mesh_builtin.py | 2 +- pyhope/mesh/topology/mesh_topology.py | 2 +- pyhope/readintools/commandline.py | 7 +++---- pyhope/readintools/readintools.py | 16 ++++++++-------- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/pyhope/__init__.py b/pyhope/__init__.py index 44bf4bee..1c84626d 100644 --- a/pyhope/__init__.py +++ b/pyhope/__init__.py @@ -27,23 +27,27 @@ # Standard libraries # ---------------------------------------------------------------------------------------------------------------------------------- from collections import namedtuple +from collections.abc import Callable from contextlib import contextmanager from functools import update_wrapper from typing import final +from typing import ParamSpec, TypeVar # ---------------------------------------------------------------------------------------------------------------------------------- # Third-party libraries # ---------------------------------------------------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------------------------------------------------- # Local imports # ---------------------------------------------------------------------------------------------------------------------------------- +P = ParamSpec('P') +R = TypeVar( 'R') # ================================================================================================================================== -def _staticwrapper(func): +def _staticwrapper(func: Callable[P, R]) -> Callable[P, R]: """ Custom helper to lift the (annotations, doc, etc.) to the staticmethod """ # Create a wrapper that carries the metadata - def wrapper(*args, **kwargs): + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: return func(*args, **kwargs) # Lift metadata (annotations, doc, etc.) to the wrapper diff --git a/pyhope/mesh/mesh_builtin.py b/pyhope/mesh/mesh_builtin.py index bc1d8090..9e2b904c 100644 --- a/pyhope/mesh/mesh_builtin.py +++ b/pyhope/mesh/mesh_builtin.py @@ -248,7 +248,7 @@ def MeshCartesian() -> meshio.Mesh: gmsh.model.geo.mesh.setRecombine(2, 1) # Create the surface loop - gmsh.model.geo.addSurfaceLoop([s for s in s], zone+1) + gmsh.model.geo.addSurfaceLoop(list(s), zone+1) gmsh.model.geo.synchronize() diff --git a/pyhope/mesh/topology/mesh_topology.py b/pyhope/mesh/topology/mesh_topology.py index 034384f8..b7b40e4a 100644 --- a/pyhope/mesh/topology/mesh_topology.py +++ b/pyhope/mesh/topology/mesh_topology.py @@ -166,7 +166,7 @@ def MeshChangeElemType(mesh: meshio.Mesh) -> meshio.Mesh: # If meshcells is empty, we fake it assign it to Zone1 if len(meshcells) == 0: - meshcells = tuple(('Zone1', {k: np.array([i for i in range(len(v))])}) for k, v in mesh.cells_dict.items() + meshcells = tuple(('Zone1', {k: np.array(list(range(len(v))))}) for k, v in mesh.cells_dict.items() if k.startswith('hexahedron')) nTotalElems = sum(cdata.shape[0] for _, zdata in meshcells for cdata in cast(dict, zdata).values()) diff --git a/pyhope/readintools/commandline.py b/pyhope/readintools/commandline.py index 5bc2a262..57902562 100644 --- a/pyhope/readintools/commandline.py +++ b/pyhope/readintools/commandline.py @@ -59,7 +59,7 @@ def separator(length: int = STD_LENGTH) -> str: class CommandLine: """ Parse command line arguments, both explicit [*.ini] and flags [--] """ - def __init__(self, argv, name: str, version: str, commit: Optional[str]) -> None: + def __init__(self, argv: list[str], name: str, version: str, commit: Optional[str]) -> None: # Local imports ---------------------------------------- import pyhope.config.config as config from pyhope.output.output import Colors @@ -92,11 +92,10 @@ def __init__(self, argv, name: str, version: str, commit: Optional[str]) -> None if isinstance(default, bool): default = 'T' if default else 'F' - help = config.prms[key]['help'] if config.prms[key]['help'] else '' + help = config.prms[key]['help'] or '' self.helpjoin(f'{key:<{PAR_LENGTH}} = {default:>{DEF_LENGTH}} ! {help}') - def __enter__(self) -> tuple[Namespace, list]: # Setup an argument parser and add know arguments _ = parser = argparse.ArgumentParser(prog = self.name, # noqa: E251 @@ -143,5 +142,5 @@ def __enter__(self) -> tuple[Namespace, list]: def __exit__(self, *args: object) -> None: return None - def helpjoin(self, end) -> None: + def helpjoin(self, end: str) -> None: self.help = os.linesep.join([self.help, end]) diff --git a/pyhope/readintools/readintools.py b/pyhope/readintools/readintools.py index c39c1cd2..97f63dc1 100644 --- a/pyhope/readintools/readintools.py +++ b/pyhope/readintools/readintools.py @@ -59,7 +59,7 @@ class MultiOrderedDict(OrderedDict): thus overload the ConfigParser with this new dict_type """ @override - def __setitem__(self, key, value) -> None: + def __setitem__(self, key: str, value: list | str) -> None: if isinstance(value, list) and key in self: self[key].extend(value) else: @@ -205,7 +205,7 @@ def CreateStr(string: str, help: Optional[str] = None, default: Optional[str] = 'multiple': multiple} -def CreateReal(string: str, help: Optional[str] = None, default: Optional[float] = None, multiple=False) -> None: +def CreateReal(string: str, help: Optional[str] = None, default: Optional[float] = None, multiple: bool = False) -> None: # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ @@ -219,7 +219,7 @@ def CreateReal(string: str, help: Optional[str] = None, default: Optional[float] 'multiple': multiple} -def CreateInt(string: str, help: Optional[str] = None, default: Optional[int] = None, multiple=False) -> None: +def CreateInt(string: str, help: Optional[str] = None, default: Optional[int] = None, multiple: bool = False) -> None: # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ @@ -233,7 +233,7 @@ def CreateInt(string: str, help: Optional[str] = None, default: Optional[int] = 'multiple': multiple} -def CreateLogical(string: str, help: Optional[str] = None, default: Optional[bool] = None, multiple=False) -> None: +def CreateLogical(string: str, help: Optional[str] = None, default: Optional[bool] = None, multiple: bool = False) -> None: # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ @@ -247,7 +247,7 @@ def CreateLogical(string: str, help: Optional[str] = None, default: Optional[boo 'multiple': multiple} -def CreateIntFromString(string: str, help: Optional[str] = None, default: Optional[str] = None, multiple=False) -> None: +def CreateIntFromString(string: str, help: Optional[str] = None, default: Optional[str] = None, multiple: bool = False) -> None: # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ @@ -263,7 +263,7 @@ def CreateIntFromString(string: str, help: Optional[str] = None, default: Option 'multiple': multiple} -def CreateIntOption(string: str, name, number) -> None: +def CreateIntOption(string: str, name: str, number: int) -> None: # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ @@ -273,7 +273,7 @@ def CreateIntOption(string: str, name, number) -> None: config.prms[string]['mapping'].update({number: name}) -def CreateRealArray(string: str, nReals, help: Optional[str] = None, default: Optional[str] = None, multiple=False) -> None: +def CreateRealArray(string: str, nReals: int, help: Optional[str] = None, default: Optional[str] = None, multiple: bool = False) -> None: # noqa: E501 # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ @@ -288,7 +288,7 @@ def CreateRealArray(string: str, nReals, help: Optional[str] = None, default: Op 'multiple': multiple} -def CreateIntArray(string: str, nInts, help: Optional[str] = None, default: Optional[str] = None, multiple=False) -> None: +def CreateIntArray(string: str, nInts: int, help: Optional[str] = None, default: Optional[str] = None, multiple: bool = False) -> None: # noqa: E501 # Local imports ---------------------------------------- import pyhope.config.config as config # ------------------------------------------------------ From aa0d41e31f8f2583fc9a3049792b7c3c86163760 Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 17:04:56 +0100 Subject: [PATCH 58/59] Linting: Upgrade pyproject.toml --- pyproject.toml | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a22598df..23a4aa48 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -161,21 +161,36 @@ target-version = "py310" [tool.ruff.lint] extend-select = [ + # "ANN", # flake8-annotations "B", # flake8-bugbear + "C4", # flake8-comprehensions + "FA", # flake8-future-annotations + "RET", # flake8-return + "SIM", # flake8-simplify + "SLOT", # flake8-slots + "TID", # flake8-tidy-imports + "FURB", # refurb + "I", # isort + "NPY", # NumPy-specific rules + # "RUF", # Ruff-specific rules ] ignore = [ - "EXE001", # shebang-not-executable - we use shebang as file format identifier - "I001", # unsorted-imports - we use logical sorting instead of alphabetical - "RET501", # unnecessary-return-none - we want to be explicit about our return values - "RUF100", # unused-noqa - we want to have multiple linters, thus sometimes more exceptions are necessary - "UP009", # utf8-encoding-declaration - we want to be explicit about our encoding - "UP007", # non-pep604-annotation-union - we want explicit typing.Union annotations - "UP045", # non-pep604-annotation-optional - we want explicit typing.Optional annotations - "PLR0402", # manual-from-import - we want every import specify the module name + "EXE001", # shebang-not-executable - we use shebang as file format identifier + "I001", # unsorted-imports - we use logical sorting instead of alphabetical + "RET501", # unnecessary-return-none - we want to be explicit about our return values + "RUF001", # ambiguous-unicode-character-string - we want to use all characters + "RUF100", # unused-noqa - we want to have multiple linters, thus sometimes more exceptions are necessary + "UP009", # utf8-encoding-declaration - we want to be explicit about our encoding + "UP007", # non-pep604-annotation-union - we want explicit typing.Union annotations + "UP045", # non-pep604-annotation-optional - we want explicit typing.Optional annotations + "PLR0402", # manual-from-import - we want every import specify the module name + # INFO: False positives + "RET503", # implicit-return - ruff does not detect hopout.error[NoReturn] # TODO: These should be fixed eventually - "BLE001", # blind-except - narrow errors and exceptions - "S110", # try-except-pass - implement feature.logger branch - "S112", # try-except-continue - implement feature.logger branch + "ANN002", # missing-type-args - determine non-trivial types + "BLE001", # blind-except - narrow errors and exceptions + "S110", # try-except-pass - implement feature.logger branch + "S112", # try-except-continue - implement feature.logger branch ] [tool.ruff.format] From 1f4582365d7e91629c745712021ae8db199c7e5c Mon Sep 17 00:00:00 2001 From: Patrick Kopper Date: Fri, 13 Mar 2026 17:13:26 +0100 Subject: [PATCH 59/59] Linting: Fix no-matching-overload --- pyhope/mesh/reader/reader_gmsh.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyhope/mesh/reader/reader_gmsh.py b/pyhope/mesh/reader/reader_gmsh.py index 76c503de..8f002e7c 100644 --- a/pyhope/mesh/reader/reader_gmsh.py +++ b/pyhope/mesh/reader/reader_gmsh.py @@ -437,7 +437,7 @@ def BCCGNS_Unstructured( mesh: meshio.Mesh, cellsets = mesh.cell_sets # Convert the cellsets to a list of lists for easier manipulation for k, v in cellsets.items(): - cellsets[k] = [cell.tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell for cell in v] + cellsets[k] = [cast(np.ndarray, cell).tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell for cell in v] for zoneBC in zoneBCs: # Lists to collect centroids @@ -638,7 +638,7 @@ def BCCGNS_Structured(mesh: meshio.Mesh, cellsets = mesh.cell_sets # Convert the cellsets to a list of lists for easier manipulation for k, v in cellsets.items(): - cellsets[k] = [cell.tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell for cell in v] + cellsets[k] = [cast(np.ndarray, cell).tolist() if isinstance(cell, (np.ndarray, np.generic)) else cell for cell in v] # Load the zone BCs for zoneBC, bcData in zone['ZoneBC'].items():