Skip to content

Commit

Permalink
Merge pull request #2163 from mikedh/feat/typeguard
Browse files Browse the repository at this point in the history
Release: Start running typeguard
  • Loading branch information
mikedh committed Feb 26, 2024
2 parents 95c5431 + 3c62b0b commit 3966450
Show file tree
Hide file tree
Showing 21 changed files with 211 additions and 188 deletions.
15 changes: 14 additions & 1 deletion Dockerfile
Expand Up @@ -72,12 +72,25 @@ RUN pip install -e .[all]
# check formatting
RUN ruff trimesh



## TODO : get typeguard to pass on more/all of the codebase
## this is running on a very arbitrary subset right now!
RUN pytest \
--typeguard-packages=trimesh.scene,trimesh.base \
-p no:ALL_DEPENDENCIES \
-p no:INCLUDE_RENDERING \
-p no:cacheprovider tests/test_s*


# run pytest wrapped with xvfb for simple viewer tests
RUN xvfb-run pytest --cov=trimesh \
RUN xvfb-run pytest \
--cov=trimesh \
-p no:ALL_DEPENDENCIES \
-p no:INCLUDE_RENDERING \
-p no:cacheprovider tests


# set codecov token as a build arg to upload
ARG CODECOV_TOKEN=""
RUN curl -Os https://uploader.codecov.io/latest/linux/codecov && \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -144,7 +144,7 @@ print(mesh.bounding_box_oriented.volume,
* Determine if a mesh is watertight, convex, etc.
* Uniformly sample the surface of a mesh
* Ray-mesh queries including location, triangle index, etc.
* Boolean operations on meshes (intersection, union, difference) using OpenSCAD or Blender as a back end. Note that mesh booleans in general are usually slow and unreliable
* Boolean operations on meshes (intersection, union, difference) using Manifold3D or Blender Note that mesh booleans in general are usually slow and unreliable
* Voxelize watertight meshes
* Volume mesh generation (TETgen) using Gmsh SDK
* Smooth watertight meshes using laplacian smoothing algorithms (Classic, Taubin, Humphrey)
Expand Down
9 changes: 7 additions & 2 deletions pyproject.toml
Expand Up @@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"]
[project]
name = "trimesh"
requires-python = ">=3.7"
version = "4.1.5"
version = "4.1.6"
authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}]
license = {file = "LICENSE.md"}
description = "Import, export, process, analyze and view triangular meshes."
Expand Down Expand Up @@ -103,7 +103,8 @@ test = [
"pymeshlab",
"pyinstrument",
"matplotlib",
"ruff"
"ruff",
"typeguard>=4.1.2"
]

# requires pip >= 21.2
Expand All @@ -129,6 +130,7 @@ select = [
"UP", # upgrade
"W", # style warnings
"YTT", # sys.version
"ISC002"
]

ignore = [
Expand All @@ -140,6 +142,9 @@ ignore = [
"B905", # zip() without an explicit strict= parameter
]

# don't allow implicit string concatenation
flake8-implicit-str-concat = {"allow-multiline" = false}

[tool.codespell]
skip = "*.js*,./docs/built/*,./docs/generate/*,./models*,*.toml"
ignore-words-list = "nd,coo,whats,bu,childs,mis,filetests"
47 changes: 22 additions & 25 deletions trimesh/base.py
Expand Up @@ -7,7 +7,6 @@

import copy
import warnings
from typing import Any, Dict, List, Optional, Tuple, Union

import numpy as np
from numpy import float64, int64, ndarray
Expand Down Expand Up @@ -43,7 +42,7 @@
from .parent import Geometry3D
from .scene import Scene
from .triangles import MassProperties
from .typed import ArrayLike, NDArray
from .typed import Any, ArrayLike, Dict, List, NDArray, Optional, Tuple, Union
from .visual import ColorVisuals, TextureVisuals, create_visual

try:
Expand Down Expand Up @@ -72,8 +71,8 @@
class Trimesh(Geometry3D):
def __init__(
self,
vertices: Optional[NDArray[float64]] = None,
faces: Optional[NDArray[int64]] = None,
vertices: Optional[ArrayLike] = None,
faces: Optional[ArrayLike] = None,
face_normals: Optional[NDArray[float64]] = None,
vertex_normals: Optional[NDArray[float64]] = None,
face_colors: Optional[NDArray[float64]] = None,
Expand Down Expand Up @@ -451,7 +450,7 @@ def vertices(self) -> NDArray[float64]:
return self._data.get("vertices", np.empty(shape=(0, 3), dtype=float64))

@vertices.setter
def vertices(self, values: NDArray[float64]):
def vertices(self, values: ArrayLike):
"""
Assign vertex values to the mesh.
Expand Down Expand Up @@ -491,7 +490,7 @@ def vertex_normals(self) -> NDArray[float64]:
return vertex_normals

@vertex_normals.setter
def vertex_normals(self, values: NDArray[float64]) -> None:
def vertex_normals(self, values: ArrayLike) -> None:
"""
Assign values to vertex normals.
Expand Down Expand Up @@ -1156,8 +1155,8 @@ def merge_vertices(

def update_vertices(
self,
mask: NDArray[bool],
inverse: Optional[NDArray] = None,
mask: ArrayLike,
inverse: Optional[ArrayLike] = None,
) -> None:
"""
Update vertices with a mask.
Expand Down Expand Up @@ -1222,7 +1221,7 @@ def update_vertices(
except BaseException:
pass

def update_faces(self, mask: NDArray[bool]) -> None:
def update_faces(self, mask: ArrayLike) -> None:
"""
In many cases, we will want to remove specific faces.
However, there is additional bookkeeping to do this cleanly.
Expand Down Expand Up @@ -1551,8 +1550,7 @@ def vertex_adjacency_graph(self) -> Graph:
> [1, 2, 3, 4]
"""

adjacency_g = graph.vertex_adjacency_graph(mesh=self)
return adjacency_g
return graph.vertex_adjacency_graph(mesh=self)

@caching.cache_decorator
def vertex_neighbors(self) -> List[List[int64]]:
Expand Down Expand Up @@ -2170,23 +2168,23 @@ def visual(self, value):
self._visual = value

def section(
self, plane_normal: List[int], plane_origin: List[int], **kwargs
) -> Path3D:
self, plane_normal: ArrayLike, plane_origin: ArrayLike, **kwargs
) -> Optional[Path3D]:
"""
Returns a 3D cross section of the current mesh and a plane
defined by origin and normal.
Parameters
------------
plane_normal: (3) vector for plane normal
Normal vector of section plane
plane_normal : (3,) float
Normal vector of section plane.
plane_origin : (3, ) float
Point on the cross section plane
Point on the cross section plane.
Returns
---------
intersections: Path3D or None
Curve of intersection
intersections
Curve of intersection or None if it was not hit by plane.
"""
# turn line segments into Path2D/Path3D objects
from .exchange.load import load_path
Expand Down Expand Up @@ -2214,10 +2212,10 @@ def section(

def section_multiplane(
self,
plane_origin: NDArray[float64],
plane_normal: NDArray[float64],
heights: NDArray[float64],
):
plane_origin: ArrayLike,
plane_normal: ArrayLike,
heights: ArrayLike,
) -> List[Optional[Path2D]]:
"""
Return multiple parallel cross sections of the current
mesh in 2D.
Expand All @@ -2226,7 +2224,7 @@ def section_multiplane(
------------
plane_origin : (3, ) float
Point on the cross section plane
plane_normal: (3) vector for plane normal
plane_normal : (3) float
Normal vector of section plane
heights : (n, ) float
Each section is offset by height along
Expand Down Expand Up @@ -2367,8 +2365,7 @@ def convex_hull(self) -> "Trimesh":
convex : trimesh.Trimesh
Mesh of convex hull of current mesh
"""
hull = convex.convex_hull(self)
return hull
return convex.convex_hull(self)

def sample(
self,
Expand Down
14 changes: 0 additions & 14 deletions trimesh/boolean.py
Expand Up @@ -4,7 +4,6 @@
Do boolean operations on meshes using either Blender or Manifold.
"""
import warnings

import numpy as np

Expand Down Expand Up @@ -172,22 +171,9 @@ def boolean_manifold(
return out_mesh


def boolean_scad(*args, **kwargs):
warnings.warn(
"The OpenSCAD interface is deprecated, and Trimesh will instead"
" use Manifold ('manifold'), which should be equivalent. In future versions"
" of Trimesh, attempting to use engine 'scad' may raise an error.",
DeprecationWarning,
stacklevel=2,
)
return boolean_manifold(*args, **kwargs)


# which backend boolean engines
_engines = {
None: boolean_manifold,
"auto": boolean_manifold,
"manifold": boolean_manifold,
"scad": boolean_scad,
"blender": interfaces.blender.boolean,
}
8 changes: 4 additions & 4 deletions trimesh/exchange/gltf.py
Expand Up @@ -15,7 +15,7 @@
from .. import rendering, resources, transformations, util, visual
from ..caching import hash_fast
from ..constants import log, tol
from ..typed import NDArray
from ..typed import NDArray, Optional
from ..util import unique_name
from ..visual.gloss import specular_to_pbr

Expand Down Expand Up @@ -775,7 +775,7 @@ def _append_mesh(
name,
tree,
buffer_items,
include_normals: bool,
include_normals: Optional[bool],
unitize_normals: bool,
mat_hashes: dict,
extension_webp: bool,
Expand Down Expand Up @@ -2057,9 +2057,9 @@ def get_schema():
from ..schemas import resolve

# get a blob of a zip file including the GLTF 2.0 schema
blob = resources.get("schema/gltf2.schema.zip", decode=False)
stream = resources.get_stream("schema/gltf2.schema.zip")
# get the zip file as a dict keyed by file name
archive = util.decompress(util.wrap_as_stream(blob), "zip")
archive = util.decompress(stream, "zip")
# get a resolver object for accessing the schema
resolver = ZipResolver(archive)
# get a loaded dict from the base file
Expand Down
2 changes: 1 addition & 1 deletion trimesh/exchange/ply.py
Expand Up @@ -285,7 +285,7 @@ def export_ply(
dtype_color = ("rgba", "<u1", (4))

# get template strings in dict
templates = resources.get("templates/ply.json", decode_json=True)
templates = resources.get_json("templates/ply.json")
# start collecting elements into a string for the header
header = [templates["intro"]]

Expand Down
4 changes: 2 additions & 2 deletions trimesh/graph.py
Expand Up @@ -16,7 +16,7 @@
from . import exceptions, grouping, util
from .constants import log, tol
from .geometry import faces_to_edges
from .typed import Optional
from .typed import List, Optional

try:
from scipy.sparse import coo_matrix, csgraph
Expand Down Expand Up @@ -324,7 +324,7 @@ def facets(mesh, engine=None):
return components


def split(mesh, only_watertight=True, adjacency=None, engine=None, **kwargs):
def split(mesh, only_watertight=True, adjacency=None, engine=None, **kwargs) -> List:
"""
Split a mesh into multiple meshes from face
connectivity.
Expand Down
4 changes: 2 additions & 2 deletions trimesh/interfaces/blender.py
Expand Up @@ -72,7 +72,7 @@ def boolean(
else:
solver_options = "FAST"
# get the template from our resources folder
template = resources.get("templates/blender_boolean.py.tmpl")
template = resources.get_string("templates/blender_boolean.py.tmpl")
script = template.replace("$OPERATION", operation)
script = script.replace("$SOLVER_OPTIONS", solver_options)
script = script.replace("$USE_SELF", f"{use_self}")
Expand All @@ -97,7 +97,7 @@ def unwrap(
raise ValueError("No blender available!")

# get the template from our resources folder
template = resources.get("templates/blender_unwrap.py")
template = resources.get_string("templates/blender_unwrap.py")
script = template.replace("$ANGLE_LIMIT", "%.6f" % angle_limit).replace(
"$ISLAND_MARGIN", "%.6f" % island_margin
)
Expand Down
76 changes: 0 additions & 76 deletions trimesh/interfaces/scad.py

This file was deleted.

0 comments on commit 3966450

Please sign in to comment.