mmgpy 0.5.0__cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mmgpy/__init__.py +296 -0
- mmgpy/__main__.py +13 -0
- mmgpy/_io.py +535 -0
- mmgpy/_logging.py +290 -0
- mmgpy/_mesh.py +2286 -0
- mmgpy/_mmgpy.cpython-311-x86_64-linux-gnu.so +0 -0
- mmgpy/_mmgpy.pyi +2140 -0
- mmgpy/_options.py +304 -0
- mmgpy/_progress.py +850 -0
- mmgpy/_pyvista.py +410 -0
- mmgpy/_result.py +143 -0
- mmgpy/_transfer.py +273 -0
- mmgpy/_validation.py +669 -0
- mmgpy/_version.py +3 -0
- mmgpy/_version.py.in +3 -0
- mmgpy/bin/mmg2d_O3 +0 -0
- mmgpy/bin/mmg3d_O3 +0 -0
- mmgpy/bin/mmgs_O3 +0 -0
- mmgpy/interactive/__init__.py +24 -0
- mmgpy/interactive/sizing_editor.py +790 -0
- mmgpy/lagrangian.py +394 -0
- mmgpy/lib/libmmg2d.so +0 -0
- mmgpy/lib/libmmg2d.so.5 +0 -0
- mmgpy/lib/libmmg2d.so.5.8.0 +0 -0
- mmgpy/lib/libmmg3d.so +0 -0
- mmgpy/lib/libmmg3d.so.5 +0 -0
- mmgpy/lib/libmmg3d.so.5.8.0 +0 -0
- mmgpy/lib/libmmgs.so +0 -0
- mmgpy/lib/libmmgs.so.5 +0 -0
- mmgpy/lib/libmmgs.so.5.8.0 +0 -0
- mmgpy/lib/libvtkCommonColor-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonComputationalGeometry-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonDataModel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonExecutionModel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonMath-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonMisc-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonSystem-9.5.so.1 +0 -0
- mmgpy/lib/libvtkCommonTransforms-9.5.so.1 +0 -0
- mmgpy/lib/libvtkDICOMParser-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersCellGrid-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersExtraction-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersGeneral-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersGeometry-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersHybrid-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersHyperTree-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersModeling-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersParallel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersReduction-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersSources-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersStatistics-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersTexture-9.5.so.1 +0 -0
- mmgpy/lib/libvtkFiltersVerdict-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOCellGrid-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOGeometry-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOImage-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOLegacy-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOParallel-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOParallelXML-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOXML-9.5.so.1 +0 -0
- mmgpy/lib/libvtkIOXMLParser-9.5.so.1 +0 -0
- mmgpy/lib/libvtkImagingCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkImagingSources-9.5.so.1 +0 -0
- mmgpy/lib/libvtkParallelCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkParallelDIY-9.5.so.1 +0 -0
- mmgpy/lib/libvtkRenderingCore-9.5.so.1 +0 -0
- mmgpy/lib/libvtkdoubleconversion-9.5.so.1 +0 -0
- mmgpy/lib/libvtkexpat-9.5.so.1 +0 -0
- mmgpy/lib/libvtkfmt-9.5.so.1 +0 -0
- mmgpy/lib/libvtkjpeg-9.5.so.1 +0 -0
- mmgpy/lib/libvtkjsoncpp-9.5.so.1 +0 -0
- mmgpy/lib/libvtkkissfft-9.5.so.1 +0 -0
- mmgpy/lib/libvtkloguru-9.5.so.1 +0 -0
- mmgpy/lib/libvtklz4-9.5.so.1 +0 -0
- mmgpy/lib/libvtklzma-9.5.so.1 +0 -0
- mmgpy/lib/libvtkmetaio-9.5.so.1 +0 -0
- mmgpy/lib/libvtkpng-9.5.so.1 +0 -0
- mmgpy/lib/libvtkpugixml-9.5.so.1 +0 -0
- mmgpy/lib/libvtksys-9.5.so.1 +0 -0
- mmgpy/lib/libvtktiff-9.5.so.1 +0 -0
- mmgpy/lib/libvtktoken-9.5.so.1 +0 -0
- mmgpy/lib/libvtkverdict-9.5.so.1 +0 -0
- mmgpy/lib/libvtkzlib-9.5.so.1 +0 -0
- mmgpy/metrics.py +596 -0
- mmgpy/progress.py +69 -0
- mmgpy/py.typed +0 -0
- mmgpy/repair/__init__.py +37 -0
- mmgpy/repair/_core.py +226 -0
- mmgpy/repair/_elements.py +241 -0
- mmgpy/repair/_vertices.py +219 -0
- mmgpy/sizing.py +370 -0
- mmgpy/ui/__init__.py +97 -0
- mmgpy/ui/__main__.py +87 -0
- mmgpy/ui/app.py +1837 -0
- mmgpy/ui/parsers.py +501 -0
- mmgpy/ui/remeshing.py +448 -0
- mmgpy/ui/samples.py +249 -0
- mmgpy/ui/utils.py +280 -0
- mmgpy/ui/viewer.py +587 -0
- mmgpy-0.5.0.dist-info/METADATA +186 -0
- mmgpy-0.5.0.dist-info/RECORD +109 -0
- mmgpy-0.5.0.dist-info/WHEEL +6 -0
- mmgpy-0.5.0.dist-info/entry_points.txt +13 -0
- mmgpy-0.5.0.dist-info/licenses/LICENSE +38 -0
- share/man/man1/mmg2d.1.gz +0 -0
- share/man/man1/mmg3d.1.gz +0 -0
- share/man/man1/mmgs.1.gz +0 -0
mmgpy/_logging.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"""Logging configuration for mmgpy with Rich integration and file logging support."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
import logging
|
|
7
|
+
import os
|
|
8
|
+
from logging.handlers import RotatingFileHandler
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from rich.logging import RichHandler
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Literal
|
|
16
|
+
|
|
17
|
+
LogLevel = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
18
|
+
|
|
19
|
+
# Module-level state for file handler
|
|
20
|
+
_file_handler: RotatingFileHandler | None = None
|
|
21
|
+
|
|
22
|
+
# Track whether console handler is enabled
|
|
23
|
+
_console_enabled: bool = True
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@functools.lru_cache(maxsize=1)
|
|
27
|
+
def get_logger() -> logging.Logger:
|
|
28
|
+
"""Get or create the mmgpy logger.
|
|
29
|
+
|
|
30
|
+
This returns the underlying logger instance, which can be used for:
|
|
31
|
+
- Direct logging calls
|
|
32
|
+
- Integration with external logging frameworks
|
|
33
|
+
- Custom handler configuration
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
logging.Logger
|
|
38
|
+
The mmgpy logger instance.
|
|
39
|
+
|
|
40
|
+
Examples
|
|
41
|
+
--------
|
|
42
|
+
>>> import mmgpy
|
|
43
|
+
>>> logger = mmgpy.get_logger()
|
|
44
|
+
>>> logger.info("Custom message")
|
|
45
|
+
|
|
46
|
+
Integration with external loggers:
|
|
47
|
+
|
|
48
|
+
>>> import logging
|
|
49
|
+
>>> # Configure your own handler before importing mmgpy
|
|
50
|
+
>>> handler = logging.StreamHandler()
|
|
51
|
+
>>> handler.setFormatter(logging.Formatter('%(name)s - %(message)s'))
|
|
52
|
+
>>>
|
|
53
|
+
>>> import mmgpy
|
|
54
|
+
>>> mmgpy.configure_logging(enable_console=False) # Disable Rich
|
|
55
|
+
>>> mmgpy.get_logger().addHandler(handler) # Use your own handler
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
logger = logging.getLogger("mmgpy")
|
|
59
|
+
|
|
60
|
+
if not logger.handlers:
|
|
61
|
+
_configure_logger(logger)
|
|
62
|
+
|
|
63
|
+
return logger
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _configure_logger(logger: logging.Logger) -> None:
|
|
67
|
+
"""Configure the logger with RichHandler."""
|
|
68
|
+
if _console_enabled:
|
|
69
|
+
handler = RichHandler(
|
|
70
|
+
rich_tracebacks=True,
|
|
71
|
+
show_path=False,
|
|
72
|
+
markup=True,
|
|
73
|
+
)
|
|
74
|
+
handler.setFormatter(logging.Formatter("%(message)s"))
|
|
75
|
+
logger.addHandler(handler)
|
|
76
|
+
|
|
77
|
+
if os.environ.get("MMGPY_DEBUG"):
|
|
78
|
+
logger.setLevel(logging.DEBUG)
|
|
79
|
+
else:
|
|
80
|
+
logger.setLevel(logging.WARNING)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def configure_logging(*, enable_console: bool = True) -> None:
|
|
84
|
+
"""Configure mmgpy logging behavior.
|
|
85
|
+
|
|
86
|
+
This function allows customization of mmgpy's logging setup,
|
|
87
|
+
particularly useful when integrating with external logging frameworks.
|
|
88
|
+
|
|
89
|
+
Parameters
|
|
90
|
+
----------
|
|
91
|
+
enable_console : bool, default True
|
|
92
|
+
Whether to enable the default Rich console handler.
|
|
93
|
+
Set to False when using your own logging handlers.
|
|
94
|
+
|
|
95
|
+
Notes
|
|
96
|
+
-----
|
|
97
|
+
This function should be called BEFORE any other mmgpy operations
|
|
98
|
+
if you want to disable the default console handler. Once the logger
|
|
99
|
+
is initialized, use `get_logger()` to add your own handlers.
|
|
100
|
+
|
|
101
|
+
Examples
|
|
102
|
+
--------
|
|
103
|
+
Using mmgpy with a custom logging setup:
|
|
104
|
+
|
|
105
|
+
>>> import mmgpy
|
|
106
|
+
>>> # Disable default Rich handler
|
|
107
|
+
>>> mmgpy.configure_logging(enable_console=False)
|
|
108
|
+
>>>
|
|
109
|
+
>>> # Add your own handler
|
|
110
|
+
>>> import logging
|
|
111
|
+
>>> handler = logging.FileHandler("app.log")
|
|
112
|
+
>>> handler.setFormatter(logging.Formatter(
|
|
113
|
+
... '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
114
|
+
... ))
|
|
115
|
+
>>> mmgpy.get_logger().addHandler(handler)
|
|
116
|
+
|
|
117
|
+
Integration with structlog or loguru:
|
|
118
|
+
|
|
119
|
+
>>> import mmgpy
|
|
120
|
+
>>> mmgpy.configure_logging(enable_console=False)
|
|
121
|
+
>>> # Now configure your preferred logging library
|
|
122
|
+
>>> # mmgpy logs will go to the "mmgpy" logger namespace
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
global _console_enabled # noqa: PLW0603
|
|
126
|
+
logger = logging.getLogger("mmgpy")
|
|
127
|
+
|
|
128
|
+
if not enable_console:
|
|
129
|
+
_console_enabled = False
|
|
130
|
+
# Remove existing Rich handlers if logger already initialized
|
|
131
|
+
for handler in logger.handlers[:]:
|
|
132
|
+
if isinstance(handler, RichHandler):
|
|
133
|
+
logger.removeHandler(handler)
|
|
134
|
+
handler.close()
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def set_log_file(
|
|
138
|
+
path: str | Path | None,
|
|
139
|
+
max_bytes: int = 10_000_000,
|
|
140
|
+
backup_count: int = 5,
|
|
141
|
+
level: int | str | None = None,
|
|
142
|
+
) -> None:
|
|
143
|
+
"""Configure file logging for mmgpy.
|
|
144
|
+
|
|
145
|
+
Enables logging to a file with optional rotation. This can be used
|
|
146
|
+
alongside console logging - logs will go to both destinations.
|
|
147
|
+
|
|
148
|
+
Parameters
|
|
149
|
+
----------
|
|
150
|
+
path : str | Path | None
|
|
151
|
+
Log file path, or None to disable file logging.
|
|
152
|
+
max_bytes : int, default 10_000_000
|
|
153
|
+
Maximum file size in bytes before rotation (default 10 MB).
|
|
154
|
+
Set to 0 to disable rotation.
|
|
155
|
+
backup_count : int, default 5
|
|
156
|
+
Number of backup files to keep after rotation.
|
|
157
|
+
level : int | str | None, default None
|
|
158
|
+
Logging level for the file handler. Can be a string like "DEBUG"
|
|
159
|
+
or an integer constant from the logging module.
|
|
160
|
+
If None, uses the same level as the logger.
|
|
161
|
+
|
|
162
|
+
Examples
|
|
163
|
+
--------
|
|
164
|
+
Basic file logging:
|
|
165
|
+
|
|
166
|
+
>>> import mmgpy
|
|
167
|
+
>>> mmgpy.set_log_file("mmgpy.log")
|
|
168
|
+
>>> mesh = mmgpy.read("input.mesh")
|
|
169
|
+
>>> mesh.remesh(hmax=0.1, verbose=1) # Output goes to file and console
|
|
170
|
+
|
|
171
|
+
With rotation settings:
|
|
172
|
+
|
|
173
|
+
>>> mmgpy.set_log_file(
|
|
174
|
+
... "mmgpy.log",
|
|
175
|
+
... max_bytes=5_000_000, # 5 MB
|
|
176
|
+
... backup_count=3
|
|
177
|
+
... )
|
|
178
|
+
|
|
179
|
+
Debug level for file only (console stays at WARNING):
|
|
180
|
+
|
|
181
|
+
>>> mmgpy.set_log_file("debug.log", level="DEBUG")
|
|
182
|
+
|
|
183
|
+
Disable file logging:
|
|
184
|
+
|
|
185
|
+
>>> mmgpy.set_log_file(None)
|
|
186
|
+
|
|
187
|
+
"""
|
|
188
|
+
global _file_handler # noqa: PLW0603
|
|
189
|
+
logger = get_logger()
|
|
190
|
+
|
|
191
|
+
# Remove existing file handler
|
|
192
|
+
if _file_handler is not None:
|
|
193
|
+
logger.removeHandler(_file_handler)
|
|
194
|
+
_file_handler.close()
|
|
195
|
+
_file_handler = None
|
|
196
|
+
|
|
197
|
+
if path is None:
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
# Create parent directories if needed
|
|
201
|
+
path = Path(path)
|
|
202
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
203
|
+
|
|
204
|
+
# Create new file handler with rotation
|
|
205
|
+
_file_handler = RotatingFileHandler(
|
|
206
|
+
path,
|
|
207
|
+
maxBytes=max_bytes,
|
|
208
|
+
backupCount=backup_count,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
# Set formatter for file output (more detailed than console)
|
|
212
|
+
formatter = logging.Formatter(
|
|
213
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
|
214
|
+
)
|
|
215
|
+
_file_handler.setFormatter(formatter)
|
|
216
|
+
|
|
217
|
+
# Set level for file handler
|
|
218
|
+
# Use NOTSET (0) by default so handler defers to logger's level
|
|
219
|
+
if level is not None:
|
|
220
|
+
if isinstance(level, str):
|
|
221
|
+
level = getattr(logging, level.upper())
|
|
222
|
+
_file_handler.setLevel(level)
|
|
223
|
+
else:
|
|
224
|
+
_file_handler.setLevel(logging.NOTSET)
|
|
225
|
+
|
|
226
|
+
logger.addHandler(_file_handler)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_log_file() -> Path | None:
|
|
230
|
+
"""Get the current log file path.
|
|
231
|
+
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
Path | None
|
|
235
|
+
The current log file path, or None if file logging is disabled.
|
|
236
|
+
|
|
237
|
+
Examples
|
|
238
|
+
--------
|
|
239
|
+
>>> import mmgpy
|
|
240
|
+
>>> mmgpy.set_log_file("output.log")
|
|
241
|
+
>>> print(mmgpy.get_log_file())
|
|
242
|
+
output.log
|
|
243
|
+
>>> mmgpy.set_log_file(None)
|
|
244
|
+
>>> print(mmgpy.get_log_file())
|
|
245
|
+
None
|
|
246
|
+
|
|
247
|
+
"""
|
|
248
|
+
if _file_handler is None:
|
|
249
|
+
return None
|
|
250
|
+
return Path(_file_handler.baseFilename)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def set_log_level(level: LogLevel | int) -> None:
|
|
254
|
+
"""Set the logging level for mmgpy.
|
|
255
|
+
|
|
256
|
+
This sets the level for the logger itself. Individual handlers
|
|
257
|
+
(console, file) may have their own levels set separately.
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
level : LogLevel | int
|
|
262
|
+
The logging level. Can be a string like "DEBUG", "INFO", "WARNING",
|
|
263
|
+
"ERROR", "CRITICAL" or an integer constant from the logging module.
|
|
264
|
+
|
|
265
|
+
Examples
|
|
266
|
+
--------
|
|
267
|
+
>>> import mmgpy
|
|
268
|
+
>>> mmgpy.set_log_level("DEBUG") # Show all debug messages
|
|
269
|
+
>>> mmgpy.set_log_level("INFO") # Show info and above
|
|
270
|
+
>>> mmgpy.set_log_level("WARNING") # Default - show warnings and errors
|
|
271
|
+
|
|
272
|
+
"""
|
|
273
|
+
logger = get_logger()
|
|
274
|
+
if isinstance(level, str):
|
|
275
|
+
level = getattr(logging, level.upper())
|
|
276
|
+
logger.setLevel(level)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def enable_debug() -> None:
|
|
280
|
+
"""Enable debug logging for mmgpy.
|
|
281
|
+
|
|
282
|
+
This is equivalent to calling `set_log_level("DEBUG")` or setting
|
|
283
|
+
the `MMGPY_DEBUG` environment variable.
|
|
284
|
+
"""
|
|
285
|
+
set_log_level(logging.DEBUG)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def disable_logging() -> None:
|
|
289
|
+
"""Disable all logging output from mmgpy."""
|
|
290
|
+
set_log_level(logging.CRITICAL + 1)
|