1111from os .path import join as pathjoin
1212from sys import platform , version_info
1313from threading import Lock
14- from typing import ClassVar
14+ from typing import ClassVar , Iterable , Iterator
1515
1616
1717class MiniRacerBaseException (Exception ): # noqa: N818
@@ -25,6 +25,15 @@ def __init__(self, path):
2525 super ().__init__ (f"Native library or dependency not available at { path } " )
2626
2727
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+
2837class JSParseException (MiniRacerBaseException ):
2938 """JavaScript could not be parsed."""
3039
@@ -82,7 +91,7 @@ def _get_lib_filename(name):
8291 return prefix + name + ext
8392
8493
85- def _build_dll_handle (dll_path ):
94+ def _build_dll_handle (dll_path ) -> ctypes . CDLL :
8695 handle = ctypes .CDLL (dll_path )
8796
8897 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):
129138# modules:
130139_SNAPSHOT_FILENAME = "snapshot_blob.bin"
131140
132- _V8_FLAGS : list [ str ] = [ "--single-threaded" ]
141+ DEFAULT_V8_FLAGS = ( "--single-threaded" ,)
133142
134143
135144def _open_resource_file (filename , exit_stack ):
@@ -151,7 +160,7 @@ def _check_path(path):
151160
152161
153162@contextmanager
154- def _open_dll () :
163+ def _open_dll (flags : Iterable [ str ]) -> Iterator [ ctypes . CDLL ] :
155164 dll_filename = _get_lib_filename ("mini_racer" )
156165
157166 with ExitStack () as exit_stack :
@@ -171,31 +180,43 @@ def _open_dll():
171180 _check_path (icu_data_path )
172181 _check_path (snapshot_path )
173182
174- dll = _build_dll_handle (dll_path )
183+ handle = _build_dll_handle (dll_path )
175184
176- dll .mr_init_v8 (
177- " " .join (_V8_FLAGS ).encode ("utf-8" ),
185+ handle .mr_init_v8 (
186+ " " .join (flags ).encode ("utf-8" ),
178187 icu_data_path .encode ("utf-8" ),
179188 snapshot_path .encode ("utf-8" ),
180189 )
181190
182- yield dll
191+ yield handle
183192
184193
185194_init_lock = Lock ()
186195_dll_handle_context_manager = None
187196_dll_handle = None
188197
189198
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
191210 global _dll_handle # noqa: PLW0603
192211
193212 with _init_lock :
194213 if _dll_handle is None :
195- _dll_handle_context_manager = _open_dll ()
214+ _dll_handle_context_manager = _open_dll (flags )
196215 _dll_handle = _dll_handle_context_manager .__enter__ ()
197216 # Note: we never call _dll_handle_context_manager.__exit__() because it's
198217 # designed as a singleton. But we could if we wanted to!
218+ elif not ignore_duplicate_init :
219+ raise LibAlreadyInitializedError
199220
200221 return _dll_handle
201222
@@ -212,7 +233,7 @@ class MiniRacer:
212233 json_impl : ClassVar [object ] = json
213234
214235 def __init__ (self ):
215- self ._dll = _get_dll_handle ( )
236+ self ._dll : ctypes . CDLL = init_mini_racer ( ignore_duplicate_init = True )
216237 self .ctx = self ._dll .mr_init_context ()
217238 self .lock = Lock ()
218239
0 commit comments