diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93ab1b91a..470c80096 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,7 +6,7 @@ # use default options for ci ci: - autoupdate_schedule: "monthly" + autoupdate_schedule: "weekly" submodules: false repos: @@ -26,25 +26,29 @@ repos: - id: requirements-txt-fixer - id: trailing-whitespace -- repo: https://github.com/asottile/pyupgrade - rev: "v3.14.0" - hooks: - - id: pyupgrade - args: [--py36-plus] - -- repo: https://github.com/PyCQA/isort - rev: "5.12.0" - hooks: - - id: isort - - repo: https://github.com/psf/black rev: "23.9.1" hooks: - id: black args: [--line-length=79] -- repo: https://github.com/PyCQA/flake8 - rev: 6.1.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.291 + hooks: + - id: ruff + args: [ + --fix, + --exit-non-zero-on-fix, + ] + +- repo: https://github.com/codespell-project/codespell + rev: v2.2.5 + hooks: + - id: codespell + args: [-w] + +- repo: https://github.com/keewis/blackdoc + rev: v0.3.8 hooks: - - id: flake8 - args: [--extend-ignore=E203] + - id: blackdoc + args: [--line-length=75] diff --git a/docs/source/handle_markdown.py b/docs/source/handle_markdown.py index 6414b4bc1..68aa30305 100644 --- a/docs/source/handle_markdown.py +++ b/docs/source/handle_markdown.py @@ -100,9 +100,7 @@ def process_file( links = get_markdown_links(content) for item in links: - if item[1].startswith( - tuple(["http", "#"]) - ): # skip http links and anchors + if item[1].startswith(("http", "#")): # skip http links and anchors content = content.replace( f"[{item[0]}]({item[1]})", f"{item[0]}", diff --git a/examples/load_sample_file.py b/examples/load_sample_file.py index 806854ea1..0d8fe1609 100644 --- a/examples/load_sample_file.py +++ b/examples/load_sample_file.py @@ -30,5 +30,5 @@ def load_sample_file(filename: str, force_reload: bool = False) -> bool: f.write(response.content) return True else: - print(f"Cant load {url}, status code: {response.status_code}.") + print(f"Can't load {url}, status code: {response.status_code}.") return False diff --git a/examples/run_all_examples.py b/examples/run_all_examples.py index 32189d48d..0afb285f1 100644 --- a/examples/run_all_examples.py +++ b/examples/run_all_examples.py @@ -9,11 +9,15 @@ files_not_completed = [] for file in glob.glob(str(pathlib.Path(__file__).parent) + "/*.py"): - if file.split("/")[-1] == "run_all_examples.py": + if file.split("/")[-1] in [ + "run_all_examples.py", + "load_sample_file.py", + ]: continue print(f"Calling {file}") - proc_return = subprocess.run([sys.executable, file]) - if proc_return.returncode != 0: + try: + proc_return = subprocess.run([sys.executable, file], check=True) + except subprocess.CalledProcessError: files_not_completed.append(file) if len(files_not_completed) > 0: print( diff --git a/gustaf/create/edges.py b/gustaf/create/edges.py index 2a084c1d9..715ce8560 100644 --- a/gustaf/create/edges.py +++ b/gustaf/create/edges.py @@ -84,12 +84,10 @@ def from_data(gus_obj, data, scale=None, data_norm=None): if scale is None: if isinstance(data, str): norm = gus_obj.vertex_data.as_scalar(data, None, True) + elif data_norm is None: + norm = np.linalg.norm(increment, axis=1) else: - # compute - if data_norm is None: - norm = np.linalg.norm(increment, axis=1) - else: - norm = np.asanyarray(data_norm) + norm = np.asanyarray(data_norm) max_data_norm = norm.max() aabb_diagonal_norm = gus_obj.bounds_diagonal_norm() diff --git a/gustaf/create/faces.py b/gustaf/create/faces.py index 09ac88cbf..e0cf54ae0 100644 --- a/gustaf/create/faces.py +++ b/gustaf/create/faces.py @@ -8,9 +8,7 @@ from gustaf.faces import Faces -def box( - bounds=[[0, 0], [1, 1]], resolutions=[2, 2], simplex=False, backslash=False -): +def box(bounds=None, resolutions=None, simplex=False, backslash=False): """Create structured quadrangle or triangle block mesh. Parameters @@ -27,6 +25,10 @@ def box( face_mesh: Volumes """ + if resolutions is None: + resolutions = [2, 2] + if bounds is None: + bounds = [[0, 0], [1, 1]] if np.array(bounds).shape != (2, 2): raise ValueError("Bounds must have a dimension of (2, 2).") if len(resolutions) != 2: @@ -56,7 +58,7 @@ def to_simplex(quad, alternate=False): vice versa. Will return a tri-mesh, if input is triangular. Default diagonalization looks like this: - .. code-block:: + .. code-block:: text (3) *---* (2) | /| @@ -66,7 +68,7 @@ def to_simplex(quad, alternate=False): resembling 'slash'. - .. code-block:: + .. code-block:: text (3) *---* (2) |\\ | @@ -136,7 +138,8 @@ def to_quad(tri): each triangle face. Warning: mesh quality could be bad! ``(new) Quad Face`` - .. code-block:: + + .. code-block:: text Ref: (node_ind), face_ind diff --git a/gustaf/create/vertices.py b/gustaf/create/vertices.py index 9c2888707..fd5032c89 100644 --- a/gustaf/create/vertices.py +++ b/gustaf/create/vertices.py @@ -35,7 +35,7 @@ def raster( if len(resolutions) != len(bounds[0]) == len(bounds[1]): raise ValueError("Length of resolutions and bounds should match.") - slices = list() + slices = [] for b0, b1, r in zip(bounds[0], bounds[1], resolutions): slices.append(slice(b0, b1, int(r) * 1j)) diff --git a/gustaf/create/volumes.py b/gustaf/create/volumes.py index 999c85ff2..7c5d3bdb0 100644 --- a/gustaf/create/volumes.py +++ b/gustaf/create/volumes.py @@ -8,7 +8,7 @@ from gustaf.volumes import Volumes -def box(bounds=[[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]], resolutions=[2, 2, 2]): +def box(bounds=None, resolutions=None): """Create structured hexahedron block mesh. Parameters @@ -23,6 +23,10 @@ def box(bounds=[[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]], resolutions=[2, 2, 2]): volume_mesh: Volumes """ + if resolutions is None: + resolutions = [2, 2, 2] + if bounds is None: + bounds = [[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]] if np.array(bounds).shape != (2, 3): raise ValueError("Bounds must have a dimension of (2, 3).") if len(resolutions) != 3: diff --git a/gustaf/edges.py b/gustaf/edges.py index d62506741..f7ab539c8 100644 --- a/gustaf/edges.py +++ b/gustaf/edges.py @@ -365,7 +365,7 @@ def dashed(self, spacing=None): ``dashed edges`` - .. code-block:: + .. code-block:: text o--------o o--------o o--------o |<------>| |<-->| diff --git a/gustaf/faces.py b/gustaf/faces.py index 29000b820..75dd593b8 100644 --- a/gustaf/faces.py +++ b/gustaf/faces.py @@ -114,7 +114,7 @@ def __init__( elif elements is not None: self.faces = elements - self.BC = dict() + self.BC = {} @helpers.data.ComputedMeshData.depends_on(["elements"]) def edges(self): diff --git a/gustaf/helpers/data.py b/gustaf/helpers/data.py index 27495b0ec..76941c835 100644 --- a/gustaf/helpers/data.py +++ b/gustaf/helpers/data.py @@ -31,7 +31,7 @@ def __array_finalize__(self, obj): """Sets default flags for any arrays that maybe generated based on tracked array.""" self._modified = True - self._source = int(0) + self._source = 0 if isinstance(obj, type(self)): if isinstance(obj._source, int): @@ -53,7 +53,7 @@ def _set_modified(self): if isinstance(self._source, type(self)): self._source._modified = True - def copy(self, *args, **kwargs): + def copy(self, *_args, **_kwargs): """copy gives np.ndarray. no more tracking. @@ -170,10 +170,11 @@ def make_tracked_array(array, dtype=None, copy=True): array = [] # make sure it is contiguous then view it as our subclass tracked = np.ascontiguousarray(array, dtype=dtype) - if copy: - tracked = tracked.copy().view(TrackedArray) - else: - tracked = tracked.view(TrackedArray) + tracked = ( + tracked.copy().view(TrackedArray) + if copy + else tracked.view(TrackedArray) + ) # should always be contiguous here assert tracked.flags["C_CONTIGUOUS"] @@ -196,7 +197,7 @@ def __init__(self, helpee): GustafBase objects would probably make the most sense here. """ self._helpee = helpee - self._saved = dict() + self._saved = {} def __setitem__(self, key, value): """Raise Error to disable direct value setting. @@ -222,7 +223,7 @@ def __getitem__(self, key): -------- value: object """ - if key in self._saved.keys(): + if key in self._saved: return self._saved[key] else: @@ -247,7 +248,7 @@ def clear(self): """ Clears saved data by reassigning new dict """ - self._saved = dict() + self._saved = {} def get(self, key, default_values=None): """Returns stored item if the key exists. Else, given default value. If @@ -263,7 +264,7 @@ def get(self, key, default_values=None): -------- value: object """ - if key in self._saved.keys(): + if key in self._saved: return self._saved[key] else: return default_values @@ -302,7 +303,7 @@ class ComputedData(DataHolder): __slots__ = () - def __init__(self, helpee, **kwargs): + def __init__(self, helpee, **_kwargs): """Stores last computed values. Keys are expected to be the same as helpee's function that computes the @@ -334,26 +335,26 @@ def depends_on(cls, var_names, make_property=False): """ def inner(func): - # followings are done once while modules are loaded + # following are done once while modules are loaded # just subclass this class to make a special helper # for each helpee class. assert isinstance(var_names, list), "var_names should be a list" # initialize property # _depends is dict(str: list) if cls._depends is None: - cls._depends = dict() + cls._depends = {} if cls._depends.get(func.__name__, None) is None: - cls._depends[func.__name__] = list() + cls._depends[func.__name__] = [] # add dependency info cls._depends[func.__name__].extend(var_names) # _inv_depends is dict(str: list) if cls._inv_depends is None: - cls._inv_depends = dict() + cls._inv_depends = {} # add inverse dependency for vn in var_names: if cls._inv_depends.get(vn, None) is None: - cls._inv_depends[vn] = list() + cls._inv_depends[vn] = [] cls._inv_depends[vn].append(func.__name__) @@ -373,7 +374,7 @@ def compute_or_return_saved(*args, **kwargs): recompute = kwargs.get("recompute", True) # computed arrays are called _computed. - # loop over dependees and check if they are modified + # loop over dependencies and check if they are modified for dependee_str in cls._depends[func.__name__]: dependee = getattr(self, dependee_str) # is modified? diff --git a/gustaf/helpers/options.py b/gustaf/helpers/options.py index 81708258b..e45caee62 100644 --- a/gustaf/helpers/options.py +++ b/gustaf/helpers/options.py @@ -145,13 +145,13 @@ def make_valid_options(*options): ------- valid_options: dict() """ - valid_options = dict() + valid_options = {} for opt in options: if not isinstance(opt, Option): raise TypeError("Please use `Option` to define options.") if not valid_options.get(opt.backend, False): - valid_options[opt.backend] = dict() + valid_options[opt.backend] = {} valid_options[opt.backend][opt.key] = opt @@ -170,7 +170,7 @@ class ShowOption: __slots__ = ("_helpee", "_options", "_backend") - _valid_options = dict() + _valid_options = {} _helps = None @@ -186,11 +186,11 @@ def __init__(self, helpee): f"This show option is for {self._helps}. " f"Given helpee is {type(helpee)}." ) - self._options = dict() + self._options = {} self._backend = settings.VISUALIZATION_BACKEND # initialize backend specific option holder - self._options[self._backend] = dict() + self._options[self._backend] = {} def __repr__(self): """ @@ -204,7 +204,7 @@ def __repr__(self): ------- description: str """ - valid_and_current = list() + valid_and_current = [] for vo in self._valid_options[self._backend].values(): valid = str(vo) current = "" @@ -231,7 +231,7 @@ def __setitem__(self, key, value): ------- None """ - if key in self._valid_options[self._backend].keys(): + if key in self._valid_options[self._backend]: # valid type check if not isinstance( value, self._valid_options[self._backend][key].allowed_types @@ -253,7 +253,7 @@ def __setitem__(self, key, value): ) self._backend = value if not self._options.get(self._backend, False): - self._options[self._backend] = dict() + self._options[self._backend] = {} else: raise ValueError(f"{key} is an invalid option for {self._helps}.") @@ -273,7 +273,7 @@ def __getitem__(self, key): if isinstance(key, str): return self._options[self._backend][key] elif hasattr(key, "__iter__"): - items = dict() + items = {} for k in key: if k in self._options[self._backend]: items[k] = self._options[self._backend][k] @@ -383,7 +383,7 @@ def clear(self): """ self._options.clear() # put back default backend option dict - self._options[self._backend] = dict() + self._options[self._backend] = {} def pop(self, *args, **kwargs): """ @@ -417,10 +417,7 @@ def copy_valid_options(self, copy_to, keys=None): raise TypeError("copy_to should be a ShowOption") valid_keys = copy_to.valid_keys() - if keys is not None: - items = self[keys].items() - else: - items = self.items() + items = self[keys].items() if keys is not None else self.items() for key, value in items: if key in valid_keys: diff --git a/gustaf/helpers/raise_if.py b/gustaf/helpers/raise_if.py index 7656c8929..f36cdb7cd 100644 --- a/gustaf/helpers/raise_if.py +++ b/gustaf/helpers/raise_if.py @@ -25,7 +25,7 @@ def invalid_inherited_attr(attr_name, qualname, property_=False): behaves same as func if `property_` is correctly defined """ - def raiser(self): + def raiser(): raise AttributeError( f"{attr_name} is not supported from {qualname} " "and its subclasses thereof." @@ -59,7 +59,7 @@ def __init__(self, lib_name: str, error_message: Optional[str] = None): f"{original_message}" ) - def __call__(self, *args: Any, **kwds: Any) -> Any: + def __call__(self, *_args: Any, **_kwargs: Any) -> Any: """Is called when the object is called by object(). Will notify the user, that the functionality is not accessible diff --git a/gustaf/io/meshio.py b/gustaf/io/meshio.py index 7254a9e11..1bcbf6522 100644 --- a/gustaf/io/meshio.py +++ b/gustaf/io/meshio.py @@ -93,6 +93,7 @@ def export(mesh, fname, submeshes=None, **kwargs): .. code-block:: python import gustaf + # define coordinates v = np.array( [ @@ -126,7 +127,7 @@ def export(mesh, fname, submeshes=None, **kwargs): vertices=v, faces=tf, ) - gustaf.io.meshio.export(mesh, 'tri-mesh.stl') + gustaf.io.meshio.export(mesh, "tri-mesh.stl") Parameters ------------ @@ -169,15 +170,14 @@ def export(mesh, fname, submeshes=None, **kwargs): # Iterate the meshes and extract the element information in meshio format for m in meshes: whatami = m.whatami - if whatami not in meshio_dict.keys(): + if whatami not in meshio_dict: raise NotImplementedError( f"{whatami}-type meshes not supported (yet)." ) + elif np.any(m.elements > len(m.vertices) - 1): + raise ValueError("Invalid vertex IDs in submesh connectivity.") else: - if np.any(m.elements > len(m.vertices) - 1): - raise ValueError("Invalid vertex IDs in submesh connectivity.") - else: - cells.append((meshio_dict[whatami], m.elements)) + cells.append((meshio_dict[whatami], m.elements)) # Export data to meshio and write file meshio.Mesh( diff --git a/gustaf/io/mixd.py b/gustaf/io/mixd.py index 043478226..b8fdfd12c 100644 --- a/gustaf/io/mixd.py +++ b/gustaf/io/mixd.py @@ -71,12 +71,12 @@ def load( # connec connec = None try: - connec = (np.fromfile(mien, dtype=">i") - int(1)).astype(np.int32) + connec = (np.fromfile(mien, dtype=">i") - 1).astype(np.int32) except BaseException: log.debug(f"mien file, `{mien}`, does not exist. Skipping.") # boundary conditions - bcs = dict() + bcs = {} try: bcs_in = np.fromfile(mrng, dtype=">i").astype(np.int32) # flattened uniq_bcs_in = np.unique(bcs_in) @@ -94,8 +94,8 @@ def load( # reshape connec if connec is not None: - ncol = int(3) if simplex and not volume else int(4) - ncol = int(8) if ncol == int(4) and volume and not simplex else ncol + ncol = 3 if simplex and not volume else 4 + ncol = 8 if ncol == 4 and volume and not simplex else ncol connec = connec.reshape(-1, ncol) diff --git a/gustaf/io/nutils.py b/gustaf/io/nutils.py index 651916b16..261d01f97 100644 --- a/gustaf/io/nutils.py +++ b/gustaf/io/nutils.py @@ -43,14 +43,11 @@ def load(fname): simplex = True connec = nodes - if vertices.shape[1] == 2: - volume = False - else: - volume = True + volume = vertices.shape[1] != 2 # reshape connec try: - ncol = int(3) if simplex and not volume else int(4) + ncol = 3 if simplex and not volume else 4 connec = connec.reshape(-1, ncol) mesh = Volumes(vertices, connec) if volume else Faces(vertices, connec) except BaseException: @@ -117,14 +114,14 @@ def to_nutils_simplex(mesh): else: raise TypeError("Only Triangle and Tetrahedrons are accepted.") - dic_to_nutils = dict() + dic_to_nutils = {} # Sort the Node IDs for each Element. sort_array = np.argsort(elements, axis=1) elements_sorted = np.take_along_axis(elements, sort_array, axis=1) # Let`s get the Boundaries - bcs = dict() + bcs = {} bcs_in = mixd.make_mrng(mesh) bcs_in = np.ndarray.reshape( bcs_in, (int(len(bcs_in) / (dimension + 1)), (dimension + 1)) diff --git a/gustaf/settings.py b/gustaf/settings.py index ca7385bf5..556f5dbbc 100644 --- a/gustaf/settings.py +++ b/gustaf/settings.py @@ -11,11 +11,11 @@ # OPTIONS are <"vedo" | "trimesh" | "matplotlib"> VISUALIZATION_BACKEND = "vedo" -VEDO_DEFAULT_OPTIONS = dict( - vertex=dict(), - edges=dict(), - faces=dict(), - volumes=dict(), -) +VEDO_DEFAULT_OPTIONS = { + "vertex": {}, + "edges": {}, + "faces": {}, + "volumes": {}, +} NTHREADS = 1 diff --git a/gustaf/show.py b/gustaf/show.py index 9b0e23e99..79d20bc70 100644 --- a/gustaf/show.py +++ b/gustaf/show.py @@ -49,7 +49,7 @@ def show(*gus_obj, **kwargs): if vis_b.startswith("vedo"): return show_vedo(*gus_obj, **kwargs) - elif vis_b.startswith("trimesh"): + elif vis_b.startswith("trimesh"): # noqa: SIM114 pass elif vis_b.startswith("matplotlib"): pass @@ -161,8 +161,8 @@ def cam_tuple_to_list(dict_cam): list_of_showables = [] for sl in show_list: if not isinstance(sl, list): - sl = [sl] - for k, item in enumerate(sl): + sl = [sl] # noqa: PLW2901 + for _k, item in enumerate(sl): if hasattr(item, "showable"): tmp_showable = item.showable(backend="vedo", **kwargs) # splines return dict @@ -227,7 +227,7 @@ def _vedo_showable(obj, as_dict=False, **kwargs): -------- vedo_obj: vedo obj """ - # incase kwargs are defined, we will make a copy of the object and + # in case kwargs are defined, we will make a copy of the object and # try to overwrite all the applicable kwargs. if kwargs: # keep original ones and assign new show_options temporarily @@ -248,7 +248,7 @@ def _vedo_showable(obj, as_dict=False, **kwargs): vedo_obj = obj.show_options._initialize_showable() # as dict? if as_dict: - return_as_dict = dict() + return_as_dict = {} # set common values. Could be a perfect place to try :=, but we want to # support p3.6. @@ -319,14 +319,12 @@ def _vedo_showable(obj, as_dict=False, **kwargs): # at last, scalarbar sb_kwargs = obj.show_options.get("scalarbar", None) if sb_kwargs is not None and sb_kwargs is not False: - sb_kwargs = dict() if isinstance(sb_kwargs, bool) else sb_kwargs + sb_kwargs = {} if isinstance(sb_kwargs, bool) else sb_kwargs vedo_obj.add_scalarbar(**sb_kwargs) sb3d_kwargs = obj.show_options.get("scalarbar3d", None) if sb3d_kwargs is not None and sb3d_kwargs is not False: - sb3d_kwargs = ( - dict() if isinstance(sb3d_kwargs, bool) else sb3d_kwargs - ) + sb3d_kwargs = {} if isinstance(sb3d_kwargs, bool) else sb3d_kwargs vedo_obj.add_scalarbar3d(**sb3d_kwargs) elif data_name is not None and vertex_data is None: @@ -367,7 +365,7 @@ def _vedo_showable(obj, as_dict=False, **kwargs): axes_kw = obj.show_options.get("axes", None) # need to explicitly check if it is false if axes_kw is not None and axes_kw is not False: - axes_kw = dict() if isinstance(axes_kw, bool) else axes_kw + axes_kw = {} if isinstance(axes_kw, bool) else axes_kw axes = vedo.Axes(vedo_obj, **axes_kw) if not as_dict: vedo_obj += axes @@ -385,12 +383,12 @@ def _vedo_showable(obj, as_dict=False, **kwargs): return return_as_dict -def _trimesh_showable(obj): +def _trimesh_showable(_obj): """""" pass -def _matplotlib_showable(obj): +def _matplotlib_showable(_obj): """""" pass @@ -484,7 +482,7 @@ def interpolate_vedo_dictcam(cameras, resolutions, spline_degree=1): ds.append([float(cam[cam_keys[3]])]) cs.append(list(cam[cam_keys[4]])) - interpolated = dict() + interpolated = {} for i, prop in enumerate([ps, fs, vs, ds, cs]): i_spline = splinepy.BSpline() i_spline.interpolate_curve( diff --git a/gustaf/utils/arr.py b/gustaf/utils/arr.py index 369310dc0..ddfefa9f7 100644 --- a/gustaf/utils/arr.py +++ b/gustaf/utils/arr.py @@ -47,12 +47,11 @@ def make_c_contiguous(array, dtype=None): if array is None: return None - if isinstance(array, np.ndarray): - if array.flags.c_contiguous: - if dtype is not None and array.dtype != dtype: - return array.astype(dtype) + if isinstance(array, np.ndarray) and array.flags.c_contiguous: + if dtype is not None and array.dtype != dtype: + return array.astype(dtype) - return array + return array if dtype: return np.ascontiguousarray(array, dtype=dtype) @@ -146,7 +145,7 @@ def unique_rows( def close_rows( - arr, tolerance=None, return_intersection=False, nthreads=None, **kwargs + arr, tolerance=None, return_intersection=False, nthreads=None, **_kwargs ): """Similar to unique_rows, but if data type is floats, use this one. Performs radius search using KDTree. Currently uses @@ -323,10 +322,9 @@ def select_with_ranges(arr, ranges): if len(masks) > 1: mask = np.zeros(arr.shape[0], dtype=bool) for i, m in enumerate(masks): - if i == 0: - mask = np.logical_or(mask, m) - else: - mask = np.logical_and(mask, m) + mask = ( + np.logical_or(mask, m) if i == 0 else np.logical_and(mask, m) + ) else: mask = masks[0] @@ -426,9 +424,8 @@ def rotation_matrix_around_axis(axis=None, rotation=None, degree=True): # Assure angle is specified if rotation is None: raise ValueError("No rotation angle specified.") - else: - if degree: - rotation = np.radians(rotation) + elif degree: + rotation = np.radians(rotation) # Check Problem dimensions if axis is None: diff --git a/gustaf/utils/connec.py b/gustaf/utils/connec.py index b7de13724..95128a1f8 100644 --- a/gustaf/utils/connec.py +++ b/gustaf/utils/connec.py @@ -16,7 +16,7 @@ def tet_to_tri(volumes): ``Tetrahedron`` - .. code-block:: + .. code-block:: text Ref: (node_ind), face_ind @@ -71,7 +71,7 @@ def hexa_to_quad(volumes): ``Hexahedron`` - .. code-block:: + .. code-block:: text (6) (7) @@ -149,7 +149,7 @@ def volumes_to_faces(volumes): def faces_to_edges(faces): """Compute edges based on following edge scheme. - .. code-block:: + .. code-block:: text Ref: (node_ind), edge_ind @@ -191,10 +191,7 @@ def faces_to_edges(faces): for i in range(vertices_per_face): # v_ind : corresponding vertex index for i value - if i == int(vertices_per_face - 1): - v_ind = 0 - else: - v_ind = i + 1 + v_ind = 0 if i == int(vertices_per_face - 1) else i + 1 edges[i::vertices_per_face, 1] = faces[:, v_ind] @@ -238,10 +235,7 @@ def range_to_edges(range_, closed=False, continuous=True): # continuous edges indices = np.repeat(indices, 2) - if closed: - indices = np.append(indices, indices[0])[1:] - else: - indices = indices[1:-1] + indices = np.append(indices, indices[0])[1:] if closed else indices[1:-1] return indices.reshape(-1, 2) @@ -270,7 +264,7 @@ def make_quad_faces(resolutions): """Given number of nodes per each dimension, returns connectivity information of a structured mesh. Counter clock wise connectivity. - .. code-block:: + .. code-block:: text (3)*------*(2) | | @@ -314,7 +308,7 @@ def make_hexa_volumes(resolutions): information of structured hexahedron elements. Counter clock wise connectivity. - .. code-block:: + .. code-block:: text (7)*-------*(6) /| /| @@ -377,7 +371,7 @@ def subdivide_edges(edges): ``Subdivided Edges`` - .. code-block:: + .. code-block:: text Edges (Lines) @@ -413,7 +407,7 @@ def subdivide_tri( ``Subdivided Faces`` - .. code-block:: + .. code-block:: text Triangles @@ -479,10 +473,10 @@ def subdivide_tri( subdivided_faces[~mask, :] = new_vertices_ids.reshape(-1, 3) if return_dict: - return dict( - vertices=new_vertices, - faces=subdivided_faces, - ) + return { + "vertices": new_vertices, + "faces": subdivided_faces, + } else: return new_vertices, subdivided_faces @@ -539,10 +533,10 @@ def subdivide_quad( ) if return_dict: - return dict( - vertices=new_vertices, - faces=subdivided_faces, - ) + return { + "vertices": new_vertices, + "faces": subdivided_faces, + } else: return new_vertices, subdivided_faces diff --git a/gustaf/utils/log.py b/gustaf/utils/log.py index eb2a1b203..ea53c7481 100644 --- a/gustaf/utils/log.py +++ b/gustaf/utils/log.py @@ -32,8 +32,8 @@ def configure(debug=False, logfile=None): # apply format using stream handler # let's use only one stream handler so that calling configure multiple # times won't duplicate printing. - new_handlers = list() - for i, h in enumerate(logger.handlers): + new_handlers = [] + for _i, h in enumerate(logger.handlers): # we skip all the stream handler. if isinstance(h, logging.StreamHandler): continue @@ -109,7 +109,7 @@ def prepended_log(message, log_func): ---------- message: str log_func: function - one of the followings - {info, debug, warning} + one of the following - {info, debug, warning} Returns ------- diff --git a/gustaf/utils/tictoc.py b/gustaf/utils/tictoc.py index c9be98c47..ea08f54da 100644 --- a/gustaf/utils/tictoc.py +++ b/gustaf/utils/tictoc.py @@ -119,6 +119,6 @@ def summary(self, log=True, print_=False): if log: self._logger(*message) if print_: - print(*message) + print(*message) # noqa: T201 return self._names.copy(), cumulative diff --git a/gustaf/vertices.py b/gustaf/vertices.py index 63f9a69dd..8fca670f2 100644 --- a/gustaf/vertices.py +++ b/gustaf/vertices.py @@ -74,7 +74,7 @@ def _initialize_vedo_showable(self): return vertices.labels( content=labels, on="points", - **self.get("label_options", dict()), + **self.get("label_options", {}), ) else: @@ -553,10 +553,7 @@ def concat(cls, *instances): def is_concatable(inst): """Return true, if it is same as type(cls)""" - if isinstance(inst, cls): - return True - else: - return False + return bool(isinstance(inst, cls)) # If only one instance is given and it is iterable, adjust # so that we will just iterate that. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..01232762f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,30 @@ +[tool.ruff] +line-length = 79 +select = [ + "E", "F", "W", # flake8 + "B", # flake8-bugbear + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "PL", # pylint + "SIM", # flake8-simplify + "T20", # flake8-print + "NPY", # numpy specific rules + "I", # isort specific rules + "UP", # pyupdate specific rules + "C400","C401","C402","C403","C404","C405" # additional pyupgrade rules +] +fixable = ["ALL"] +target-version = "py37" +ignore = [ + "PLR2004", # TODO! + "PLR0912", # Too many branches + "PLR0913", # Too many arguments to function call + "PLR0915", # Too many statements + "B904", # Within an `except` clause, raise exceptions with ... + # "PLR0911", # Too many return statements +] + +[tool.ruff.per-file-ignores] +"setup.py" = ["T201"] +"examples/*.py" = ["T201"] +"tests/*.py" = ["T201", "B018"] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1033a6aaa..000000000 --- a/setup.cfg +++ /dev/null @@ -1,6 +0,0 @@ -[isort] -profile = black -line_length = 79 - -[flake8] -extend-ignore = E203 diff --git a/tests/test_vertices_and_element_updates.py b/tests/test_vertices_and_element_updates.py index a0ff0e4e5..c01022aee 100644 --- a/tests/test_vertices_and_element_updates.py +++ b/tests/test_vertices_and_element_updates.py @@ -77,7 +77,7 @@ def test_unique_vertices(grid, request): # copy original n_original_vertices = len(grid.vertices) original_vertices = grid.vertices.copy() - # assgin new vertices + # assign new vertices # ==> stacks (original, random, original, random) grid.vertices = np.vstack( (grid.vertices, random_vertices, original_vertices, random_vertices) @@ -100,7 +100,7 @@ def test_unique_vertices(grid, request): assert all(np.tile(np.arange(n_expected_unique), 2) == unique_vs.inverse) # intersection check - should include itself as well - # also, should be sorted, assuming scipy verion is > 1.6 + # also, should be sorted, assuming scipy version is > 1.6 intersection_list = [*unique_vs.intersection] intersection_ref = [ [i, i + n_expected_unique] for i in range(n_expected_unique) @@ -147,7 +147,7 @@ def test_update_vertices(grid, request): # int based mask - let's keep 3 vertices n_original_vs = len(grid.vertices) n_vertices_to_keep = 3 - int_mask = np.random.choice( + int_mask = np.random.default_rng().choice( np.arange(n_original_vs), n_vertices_to_keep, replace=False, @@ -198,7 +198,7 @@ def test_update_elements(grid, request): n_original_es = len(grid.elements) n_elements_to_keep = 3 - int_mask = np.random.choice( + int_mask = np.random.default_rng().choice( np.arange(n_original_es), n_elements_to_keep, replace=False,