Skip to content

Commit 3966450

Browse files
authored
Merge pull request #2163 from mikedh/feat/typeguard
Release: Start running typeguard
2 parents 95c5431 + 3c62b0b commit 3966450

21 files changed

Lines changed: 211 additions & 188 deletions

File tree

Dockerfile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,25 @@ RUN pip install -e .[all]
7272
# check formatting
7373
RUN ruff trimesh
7474

75+
76+
77+
## TODO : get typeguard to pass on more/all of the codebase
78+
## this is running on a very arbitrary subset right now!
79+
RUN pytest \
80+
--typeguard-packages=trimesh.scene,trimesh.base \
81+
-p no:ALL_DEPENDENCIES \
82+
-p no:INCLUDE_RENDERING \
83+
-p no:cacheprovider tests/test_s*
84+
85+
7586
# run pytest wrapped with xvfb for simple viewer tests
76-
RUN xvfb-run pytest --cov=trimesh \
87+
RUN xvfb-run pytest \
88+
--cov=trimesh \
7789
-p no:ALL_DEPENDENCIES \
7890
-p no:INCLUDE_RENDERING \
7991
-p no:cacheprovider tests
8092

93+
8194
# set codecov token as a build arg to upload
8295
ARG CODECOV_TOKEN=""
8396
RUN curl -Os https://uploader.codecov.io/latest/linux/codecov && \

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ print(mesh.bounding_box_oriented.volume,
144144
* Determine if a mesh is watertight, convex, etc.
145145
* Uniformly sample the surface of a mesh
146146
* Ray-mesh queries including location, triangle index, etc.
147-
* 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
147+
* Boolean operations on meshes (intersection, union, difference) using Manifold3D or Blender Note that mesh booleans in general are usually slow and unreliable
148148
* Voxelize watertight meshes
149149
* Volume mesh generation (TETgen) using Gmsh SDK
150150
* Smooth watertight meshes using laplacian smoothing algorithms (Classic, Taubin, Humphrey)

pyproject.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ requires = ["setuptools >= 61.0", "wheel"]
55
[project]
66
name = "trimesh"
77
requires-python = ">=3.7"
8-
version = "4.1.5"
8+
version = "4.1.6"
99
authors = [{name = "Michael Dawson-Haggerty", email = "mikedh@kerfed.com"}]
1010
license = {file = "LICENSE.md"}
1111
description = "Import, export, process, analyze and view triangular meshes."
@@ -103,7 +103,8 @@ test = [
103103
"pymeshlab",
104104
"pyinstrument",
105105
"matplotlib",
106-
"ruff"
106+
"ruff",
107+
"typeguard>=4.1.2"
107108
]
108109

109110
# requires pip >= 21.2
@@ -129,6 +130,7 @@ select = [
129130
"UP", # upgrade
130131
"W", # style warnings
131132
"YTT", # sys.version
133+
"ISC002"
132134
]
133135

134136
ignore = [
@@ -140,6 +142,9 @@ ignore = [
140142
"B905", # zip() without an explicit strict= parameter
141143
]
142144

145+
# don't allow implicit string concatenation
146+
flake8-implicit-str-concat = {"allow-multiline" = false}
147+
143148
[tool.codespell]
144149
skip = "*.js*,./docs/built/*,./docs/generate/*,./models*,*.toml"
145150
ignore-words-list = "nd,coo,whats,bu,childs,mis,filetests"

trimesh/base.py

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import copy
99
import warnings
10-
from typing import Any, Dict, List, Optional, Tuple, Union
1110

1211
import numpy as np
1312
from numpy import float64, int64, ndarray
@@ -43,7 +42,7 @@
4342
from .parent import Geometry3D
4443
from .scene import Scene
4544
from .triangles import MassProperties
46-
from .typed import ArrayLike, NDArray
45+
from .typed import Any, ArrayLike, Dict, List, NDArray, Optional, Tuple, Union
4746
from .visual import ColorVisuals, TextureVisuals, create_visual
4847

4948
try:
@@ -72,8 +71,8 @@
7271
class Trimesh(Geometry3D):
7372
def __init__(
7473
self,
75-
vertices: Optional[NDArray[float64]] = None,
76-
faces: Optional[NDArray[int64]] = None,
74+
vertices: Optional[ArrayLike] = None,
75+
faces: Optional[ArrayLike] = None,
7776
face_normals: Optional[NDArray[float64]] = None,
7877
vertex_normals: Optional[NDArray[float64]] = None,
7978
face_colors: Optional[NDArray[float64]] = None,
@@ -451,7 +450,7 @@ def vertices(self) -> NDArray[float64]:
451450
return self._data.get("vertices", np.empty(shape=(0, 3), dtype=float64))
452451

453452
@vertices.setter
454-
def vertices(self, values: NDArray[float64]):
453+
def vertices(self, values: ArrayLike):
455454
"""
456455
Assign vertex values to the mesh.
457456
@@ -491,7 +490,7 @@ def vertex_normals(self) -> NDArray[float64]:
491490
return vertex_normals
492491

493492
@vertex_normals.setter
494-
def vertex_normals(self, values: NDArray[float64]) -> None:
493+
def vertex_normals(self, values: ArrayLike) -> None:
495494
"""
496495
Assign values to vertex normals.
497496
@@ -1156,8 +1155,8 @@ def merge_vertices(
11561155

11571156
def update_vertices(
11581157
self,
1159-
mask: NDArray[bool],
1160-
inverse: Optional[NDArray] = None,
1158+
mask: ArrayLike,
1159+
inverse: Optional[ArrayLike] = None,
11611160
) -> None:
11621161
"""
11631162
Update vertices with a mask.
@@ -1222,7 +1221,7 @@ def update_vertices(
12221221
except BaseException:
12231222
pass
12241223

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

1554-
adjacency_g = graph.vertex_adjacency_graph(mesh=self)
1555-
return adjacency_g
1553+
return graph.vertex_adjacency_graph(mesh=self)
15561554

15571555
@caching.cache_decorator
15581556
def vertex_neighbors(self) -> List[List[int64]]:
@@ -2170,23 +2168,23 @@ def visual(self, value):
21702168
self._visual = value
21712169

21722170
def section(
2173-
self, plane_normal: List[int], plane_origin: List[int], **kwargs
2174-
) -> Path3D:
2171+
self, plane_normal: ArrayLike, plane_origin: ArrayLike, **kwargs
2172+
) -> Optional[Path3D]:
21752173
"""
21762174
Returns a 3D cross section of the current mesh and a plane
21772175
defined by origin and normal.
21782176
21792177
Parameters
21802178
------------
2181-
plane_normal: (3) vector for plane normal
2182-
Normal vector of section plane
2179+
plane_normal : (3,) float
2180+
Normal vector of section plane.
21832181
plane_origin : (3, ) float
2184-
Point on the cross section plane
2182+
Point on the cross section plane.
21852183
21862184
Returns
21872185
---------
2188-
intersections: Path3D or None
2189-
Curve of intersection
2186+
intersections
2187+
Curve of intersection or None if it was not hit by plane.
21902188
"""
21912189
# turn line segments into Path2D/Path3D objects
21922190
from .exchange.load import load_path
@@ -2214,10 +2212,10 @@ def section(
22142212

22152213
def section_multiplane(
22162214
self,
2217-
plane_origin: NDArray[float64],
2218-
plane_normal: NDArray[float64],
2219-
heights: NDArray[float64],
2220-
):
2215+
plane_origin: ArrayLike,
2216+
plane_normal: ArrayLike,
2217+
heights: ArrayLike,
2218+
) -> List[Optional[Path2D]]:
22212219
"""
22222220
Return multiple parallel cross sections of the current
22232221
mesh in 2D.
@@ -2226,7 +2224,7 @@ def section_multiplane(
22262224
------------
22272225
plane_origin : (3, ) float
22282226
Point on the cross section plane
2229-
plane_normal: (3) vector for plane normal
2227+
plane_normal : (3) float
22302228
Normal vector of section plane
22312229
heights : (n, ) float
22322230
Each section is offset by height along
@@ -2367,8 +2365,7 @@ def convex_hull(self) -> "Trimesh":
23672365
convex : trimesh.Trimesh
23682366
Mesh of convex hull of current mesh
23692367
"""
2370-
hull = convex.convex_hull(self)
2371-
return hull
2368+
return convex.convex_hull(self)
23722369

23732370
def sample(
23742371
self,

trimesh/boolean.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
55
Do boolean operations on meshes using either Blender or Manifold.
66
"""
7-
import warnings
87

98
import numpy as np
109

@@ -172,22 +171,9 @@ def boolean_manifold(
172171
return out_mesh
173172

174173

175-
def boolean_scad(*args, **kwargs):
176-
warnings.warn(
177-
"The OpenSCAD interface is deprecated, and Trimesh will instead"
178-
" use Manifold ('manifold'), which should be equivalent. In future versions"
179-
" of Trimesh, attempting to use engine 'scad' may raise an error.",
180-
DeprecationWarning,
181-
stacklevel=2,
182-
)
183-
return boolean_manifold(*args, **kwargs)
184-
185-
186174
# which backend boolean engines
187175
_engines = {
188176
None: boolean_manifold,
189-
"auto": boolean_manifold,
190177
"manifold": boolean_manifold,
191-
"scad": boolean_scad,
192178
"blender": interfaces.blender.boolean,
193179
}

trimesh/exchange/gltf.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from .. import rendering, resources, transformations, util, visual
1616
from ..caching import hash_fast
1717
from ..constants import log, tol
18-
from ..typed import NDArray
18+
from ..typed import NDArray, Optional
1919
from ..util import unique_name
2020
from ..visual.gloss import specular_to_pbr
2121

@@ -775,7 +775,7 @@ def _append_mesh(
775775
name,
776776
tree,
777777
buffer_items,
778-
include_normals: bool,
778+
include_normals: Optional[bool],
779779
unitize_normals: bool,
780780
mat_hashes: dict,
781781
extension_webp: bool,
@@ -2057,9 +2057,9 @@ def get_schema():
20572057
from ..schemas import resolve
20582058

20592059
# get a blob of a zip file including the GLTF 2.0 schema
2060-
blob = resources.get("schema/gltf2.schema.zip", decode=False)
2060+
stream = resources.get_stream("schema/gltf2.schema.zip")
20612061
# get the zip file as a dict keyed by file name
2062-
archive = util.decompress(util.wrap_as_stream(blob), "zip")
2062+
archive = util.decompress(stream, "zip")
20632063
# get a resolver object for accessing the schema
20642064
resolver = ZipResolver(archive)
20652065
# get a loaded dict from the base file

trimesh/exchange/ply.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ def export_ply(
285285
dtype_color = ("rgba", "<u1", (4))
286286

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

trimesh/graph.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from . import exceptions, grouping, util
1717
from .constants import log, tol
1818
from .geometry import faces_to_edges
19-
from .typed import Optional
19+
from .typed import List, Optional
2020

2121
try:
2222
from scipy.sparse import coo_matrix, csgraph
@@ -324,7 +324,7 @@ def facets(mesh, engine=None):
324324
return components
325325

326326

327-
def split(mesh, only_watertight=True, adjacency=None, engine=None, **kwargs):
327+
def split(mesh, only_watertight=True, adjacency=None, engine=None, **kwargs) -> List:
328328
"""
329329
Split a mesh into multiple meshes from face
330330
connectivity.

trimesh/interfaces/blender.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def boolean(
7272
else:
7373
solver_options = "FAST"
7474
# get the template from our resources folder
75-
template = resources.get("templates/blender_boolean.py.tmpl")
75+
template = resources.get_string("templates/blender_boolean.py.tmpl")
7676
script = template.replace("$OPERATION", operation)
7777
script = script.replace("$SOLVER_OPTIONS", solver_options)
7878
script = script.replace("$USE_SELF", f"{use_self}")
@@ -97,7 +97,7 @@ def unwrap(
9797
raise ValueError("No blender available!")
9898

9999
# get the template from our resources folder
100-
template = resources.get("templates/blender_unwrap.py")
100+
template = resources.get_string("templates/blender_unwrap.py")
101101
script = template.replace("$ANGLE_LIMIT", "%.6f" % angle_limit).replace(
102102
"$ISLAND_MARGIN", "%.6f" % island_margin
103103
)

trimesh/interfaces/scad.py

Lines changed: 0 additions & 76 deletions
This file was deleted.

0 commit comments

Comments
 (0)