Coverage for trimesh/typed.py: 98%

45 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-07-31 23:55 +0000

1import io 

2import typing 

3from collections.abc import Callable, Hashable, Iterable, Mapping, Sequence 

4from io import IOBase 

5from pathlib import Path 

6from sys import version_info 

7from typing import ( 

8 IO, 

9 Any, 

10 BinaryIO, 

11 Literal, 

12 Protocol, 

13 TypeAlias, 

14 TypeGuard, 

15 TypeVar, 

16 runtime_checkable, 

17) 

18 

19import numpy 

20from numpy import dtype, float64, floating, generic, int64, integer, ndarray 

21from numpy.random import BitGenerator, Generator, SeedSequence 

22from numpy.typing import ArrayLike, DTypeLike, NDArray 

23 

24if version_info >= (3, 11): 

25 from typing import Self 

26else: 

27 Self = Any 

28 

29# most loader routes take `file_obj` which can either be 

30# a file-like object or a file path, or sometimes a dict 

31# `IOBase` is the base of every stdlib stream and is included because 

32# concrete streams like `io.BytesIO` don't satisfy the `IO` protocol 

33# under beartype — https://github.com/beartype/beartype/issues/643 

34Stream: TypeAlias = IO[str] | IO[bytes] | IOBase 

35Loadable: TypeAlias = str | Path | Stream | dict | None 

36 

37# for a function that returns "is this a file or not" 

38# but with typeguard-narrowing if the answer is yes 

39BoolIsFile: TypeAlias = TypeGuard[IO[Any]] 

40 

41# numpy integers do not inherit from python integers, i.e. 

42# if you type a function argument as an `int` and then pass 

43# a value from a numpy array like `np.ones(10, dtype=np.int64)[0]` 

44# you may have a type error. 

45# these wrappers union numpy integers and python integers 

46Integer: TypeAlias = int | integer 

47 

48# Numbers which can only be floats and will not accept integers 

49# > isinstance(np.ones(1, dtype=np.float32)[0], floating) # True 

50# > isinstance(np.ones(1, dtype=np.float32)[0], float) # False 

51Floating: TypeAlias = float | floating 

52 

53# Many arguments take "any valid number" and don't care if it 

54# is an integer or a floating point input. 

55Number: TypeAlias = Floating | Integer 

56 

57# the literals for specifying what viewer to use 

58ViewerType: TypeAlias = Callable | Literal["gl", "jupyter", "marimo"] | None 

59 

60# literal for color maps we include in the library 

61ColorMapType: TypeAlias = Literal["viridis", "magma", "inferno", "plasma"] 

62 

63# the literal for what graph backend engines are available 

64GraphEngineType: TypeAlias = Literal["networkx", "scipy"] | None 

65 

66# what 3D boolean engines are available 

67BooleanEngineType: TypeAlias = Literal["manifold", "blender"] | None 

68# what 3D boolean operations can be passed to boolean functions 

69BooleanOperationType: TypeAlias = Literal["difference", "union", "intersection"] 

70 

71# what are the supported methods for converting a mesh into voxels. 

72VoxelizationMethodsType: TypeAlias = Literal["subdivide", "ray", "binvox"] 

73 

74 

75@runtime_checkable 

76class HttpSessionLike(Protocol): 

77 """ 

78 Structural type for an HTTP session. 

79 

80 Matches `httpx.Client` and `requests.Session` so a resolver 

81 can take either without trimesh importing them directly. 

82 other duck-typed sessions are called as `get(url)` with no 

83 additional kwargs. async sessions like `aiohttp.ClientSession` 

84 can't be driven synchronously and are rejected at runtime. 

85 """ 

86 

87 def get(self, url: str, *args, **kwargs) -> Any: ... 

88 

89 

90# add numpy types like their `numpy.typing.NDArray` 

91# but with specific dimensionality, i.e. `NDArray2D[np.float64]` 

92DType = TypeVar("DType", bound=generic) 

93NDArray1D: TypeAlias = ndarray[tuple[int], dtype[DType]] 

94NDArray2D: TypeAlias = ndarray[tuple[int, int], dtype[DType]] 

95NDArray3D: TypeAlias = ndarray[tuple[int, int, int], dtype[DType]] 

96 

97# anything `numpy.random.default_rng` can normalize into a `Generator` 

98# passing a `Generator` lets a caller thread one stream through nested 

99# calls -- `default_rng` hands it back rather than re-seeding it 

100Seed: TypeAlias = Integer | Sequence[int] | SeedSequence | Generator | BitGenerator | None 

101 

102 

103# DEPRECATED : these aliases will be removed after July 2028 

104# import them from `typing`, `io`, or `numpy` instead 

105List = list 

106Dict = dict 

107Tuple = tuple 

108Set = set 

109Optional = typing.Optional 

110Union = typing.Union 

111TextIO = typing.TextIO 

112BytesIO = io.BytesIO 

113StringIO = io.StringIO 

114BufferedRandom = io.BufferedRandom 

115unsignedinteger = numpy.unsignedinteger 

116 

117 

118__all__ = [ 

119 "IO", 

120 "Any", 

121 "ArrayLike", 

122 "BinaryIO", 

123 "BoolIsFile", 

124 "Callable", 

125 "DTypeLike", 

126 "Floating", 

127 "Hashable", 

128 "HttpSessionLike", 

129 "Integer", 

130 "Iterable", 

131 "Literal", 

132 "Loadable", 

133 "Mapping", 

134 "NDArray", 

135 "NDArray1D", 

136 "NDArray2D", 

137 "NDArray3D", 

138 "Number", 

139 "Seed", 

140 "Self", 

141 "Sequence", 

142 "Stream", 

143 "ViewerType", 

144 "float64", 

145 "int64", 

146]