11
11
from os .path import join as pathjoin
12
12
from sys import platform , version_info
13
13
from threading import Lock
14
- from typing import ClassVar
14
+ from typing import ClassVar , Iterable , Iterator
15
15
16
16
17
17
class MiniRacerBaseException (Exception ): # noqa: N818
@@ -25,6 +25,15 @@ def __init__(self, path):
25
25
super ().__init__ (f"Native library or dependency not available at { path } " )
26
26
27
27
28
+ class LibAlreadyInitializedError (MiniRacerBaseException ):
29
+ """MiniRacer-wrapped V8 build not found."""
30
+
31
+ def __init__ (self ):
32
+ super ().__init__ (
33
+ "MiniRacer was already initialized before the call to init_mini_racer"
34
+ )
35
+
36
+
28
37
class JSParseException (MiniRacerBaseException ):
29
38
"""JavaScript could not be parsed."""
30
39
@@ -82,7 +91,7 @@ def _get_lib_filename(name):
82
91
return prefix + name + ext
83
92
84
93
85
- def _build_dll_handle (dll_path ):
94
+ def _build_dll_handle (dll_path ) -> ctypes . CDLL :
86
95
handle = ctypes .CDLL (dll_path )
87
96
88
97
handle .mr_init_v8 .argtypes = [ctypes .c_char_p , ctypes .c_char_p , ctypes .c_char_p ]
@@ -129,7 +138,7 @@ def _build_dll_handle(dll_path):
129
138
# modules:
130
139
_SNAPSHOT_FILENAME = "snapshot_blob.bin"
131
140
132
- _V8_FLAGS : list [ str ] = [ "--single-threaded" ]
141
+ DEFAULT_V8_FLAGS = ( "--single-threaded" ,)
133
142
134
143
135
144
def _open_resource_file (filename , exit_stack ):
@@ -151,7 +160,7 @@ def _check_path(path):
151
160
152
161
153
162
@contextmanager
154
- def _open_dll () :
163
+ def _open_dll (flags : Iterable [ str ]) -> Iterator [ ctypes . CDLL ] :
155
164
dll_filename = _get_lib_filename ("mini_racer" )
156
165
157
166
with ExitStack () as exit_stack :
@@ -171,31 +180,43 @@ def _open_dll():
171
180
_check_path (icu_data_path )
172
181
_check_path (snapshot_path )
173
182
174
- dll = _build_dll_handle (dll_path )
183
+ handle = _build_dll_handle (dll_path )
175
184
176
- dll .mr_init_v8 (
177
- " " .join (_V8_FLAGS ).encode ("utf-8" ),
185
+ handle .mr_init_v8 (
186
+ " " .join (flags ).encode ("utf-8" ),
178
187
icu_data_path .encode ("utf-8" ),
179
188
snapshot_path .encode ("utf-8" ),
180
189
)
181
190
182
- yield dll
191
+ yield handle
183
192
184
193
185
194
_init_lock = Lock ()
186
195
_dll_handle_context_manager = None
187
196
_dll_handle = None
188
197
189
198
190
- def _get_dll_handle ():
199
+ def init_mini_racer (
200
+ * , flags : Iterable [str ] = DEFAULT_V8_FLAGS , ignore_duplicate_init = False
201
+ ) -> ctypes .CDLL :
202
+ """Initialize py_mini_racer (and V8).
203
+
204
+ This function can optionally be used to set V8 flags. This function can be called
205
+ at most once, before any instances of MiniRacer are initialized. Instances of
206
+ MiniRacer will automatically call this function to initialize MiniRacer and V8.
207
+ """
208
+
209
+ global _dll_handle_context_manager # noqa: PLW0603
191
210
global _dll_handle # noqa: PLW0603
192
211
193
212
with _init_lock :
194
213
if _dll_handle is None :
195
- _dll_handle_context_manager = _open_dll ()
214
+ _dll_handle_context_manager = _open_dll (flags )
196
215
_dll_handle = _dll_handle_context_manager .__enter__ ()
197
216
# Note: we never call _dll_handle_context_manager.__exit__() because it's
198
217
# designed as a singleton. But we could if we wanted to!
218
+ elif not ignore_duplicate_init :
219
+ raise LibAlreadyInitializedError
199
220
200
221
return _dll_handle
201
222
@@ -212,7 +233,7 @@ class MiniRacer:
212
233
json_impl : ClassVar [object ] = json
213
234
214
235
def __init__ (self ):
215
- self ._dll = _get_dll_handle ( )
236
+ self ._dll : ctypes . CDLL = init_mini_racer ( ignore_duplicate_init = True )
216
237
self .ctx = self ._dll .mr_init_context ()
217
238
self .lock = Lock ()
218
239
0 commit comments