|
8 | 8 | # Determine the current operating system |
9 | 9 | system = platform.system().lower() |
10 | 10 |
|
11 | | - |
12 | 11 | # Determine the platform and choose the right library extension |
13 | 12 | if system == "linux": |
14 | 13 | lib_file = "lib3mf.so" |
|
23 | 22 | dir_path = os.path.dirname(os.path.realpath(__file__)) |
24 | 23 | lib_path = os.path.join(dir_path, lib_file) |
25 | 24 |
|
26 | | - |
27 | 25 | if not os.path.exists(lib_path): |
28 | 26 | raise ImportError(f"The required binary {lib_path} could not be found in {dir_path}") |
29 | 27 |
|
30 | 28 | # Add the path to the system path if necessary (useful for DLLs on Windows) |
31 | 29 | sys.path.append(dir_path) |
32 | 30 |
|
33 | | -# Ensure that your Lib3MF.py wraps around the shared library correctly |
34 | | -from .Lib3MF import * # Import necessary classes/functions from your Lib3MF.py |
| 31 | +# Import generated bindings |
| 32 | +from .Lib3MF import * |
| 33 | + |
| 34 | + |
| 35 | +# --------------------------- |
| 36 | +# Public helpers |
| 37 | +# --------------------------- |
35 | 38 |
|
36 | | -# Returns the raw library path |
37 | 39 | def get_library_path(): |
38 | 40 | global lib_path |
39 | 41 | return lib_path |
40 | 42 |
|
41 | | -# For existing codes that use Wrapper class directly |
| 43 | + |
42 | 44 | def get_library_path_for_wrapper(): |
43 | 45 | global lib_path |
44 | | - if system == "linux": |
45 | | - if str(lib_path).endswith(".so"): |
46 | | - return lib_path[:-3] |
47 | | - if system == "windows": |
48 | | - if str(lib_path).endswith(".dll"): |
49 | | - return lib_path[:-4] |
50 | | - if system == "darwin": |
51 | | - if str(lib_path).endswith(".dylib"): |
52 | | - return lib_path[:-6] |
53 | | - |
54 | | -# Your existing logic to use the library |
| 46 | + path_str = str(lib_path) |
| 47 | + |
| 48 | + if system == "linux" and path_str.endswith(".so"): |
| 49 | + return path_str[:-3] |
| 50 | + if system == "windows" and path_str.endswith(".dll"): |
| 51 | + return path_str[:-4] |
| 52 | + if system == "darwin" and path_str.endswith(".dylib"): |
| 53 | + return path_str[:-6] |
| 54 | + |
| 55 | + base, _ext = os.path.splitext(path_str) |
| 56 | + return base |
| 57 | + |
| 58 | + |
55 | 59 | def get_wrapper(): |
56 | | - global lib_path |
| 60 | + from . import Lib3MF as _Lib3MF |
57 | 61 | try: |
58 | | - # No need to modify lib_path here; just use it directly in your wrapper |
59 | | - return Wrapper(get_library_path_for_wrapper()) |
60 | | - except ELib3MFException as e: |
| 62 | + return _Lib3MF.Wrapper(get_library_path_for_wrapper()) |
| 63 | + except _Lib3MF.ELib3MFException as e: |
61 | 64 | print("Failed to initialize the Lib3MF wrapper: ", e) |
62 | 65 | raise |
| 66 | + |
| 67 | + |
| 68 | +# --------------------------------------------------------------------------- |
| 69 | +# PYTHON 3.13 SHUTDOWN SAFETY MONKEY PATCH |
| 70 | +# |
| 71 | +# Fixes: |
| 72 | +# Exception ignored in: Base.__del__ |
| 73 | +# AttributeError: 'NoneType' object has no attribute 'SUCCESS' |
| 74 | +# |
| 75 | +# Root cause: |
| 76 | +# During interpreter shutdown, Lib3MF.ErrorCodes becomes None. |
| 77 | +# Base.__del__ -> Wrapper.Release -> checkError -> ErrorCodes.SUCCESS |
| 78 | +# |
| 79 | +# Solution: |
| 80 | +# Patch Wrapper.checkError to NO-OP if ErrorCodes is already None. |
| 81 | +# |
| 82 | +# This preserves full runtime behavior and only affects shutdown. |
| 83 | +# --------------------------------------------------------------------------- |
| 84 | + |
| 85 | +try: |
| 86 | + from . import Lib3MF as _Lib3MF |
| 87 | + |
| 88 | + _original_checkError = _Lib3MF.Wrapper.checkError |
| 89 | + |
| 90 | + def _patched_checkError(self, instance, errorCode): |
| 91 | + ec = getattr(_Lib3MF, "ErrorCodes", None) |
| 92 | + if ec is None: |
| 93 | + # Interpreter shutdown: suppress destructor noise |
| 94 | + return |
| 95 | + return _original_checkError(self, instance, errorCode) |
| 96 | + |
| 97 | + _Lib3MF.Wrapper.checkError = _patched_checkError |
| 98 | + |
| 99 | +except Exception: |
| 100 | + # Never block import if bindings differ slightly |
| 101 | + pass |
0 commit comments