Skip to content

Commit 70a2b22

Browse files
author
Ben Creech
committed
Re-allow changing flags in case someone needs that
1 parent 95f87cb commit 70a2b22

File tree

3 files changed

+60
-11
lines changed

3 files changed

+60
-11
lines changed

src/py_mini_racer/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
from py_mini_racer import py_mini_racer
22

3+
DEFAULT_V8_FLAGS = py_mini_racer.DEFAULT_V8_FLAGS
34
JSEvalException = py_mini_racer.JSEvalException
45
JSFunction = py_mini_racer.JSFunction
56
JSOOMException = py_mini_racer.JSOOMException
67
JSObject = py_mini_racer.JSObject
78
JSParseException = py_mini_racer.JSParseException
89
JSSymbol = py_mini_racer.JSSymbol
910
JSTimeoutException = py_mini_racer.JSTimeoutException
11+
LibAlreadyInitializedError = py_mini_racer.LibAlreadyInitializedError
12+
LibNotFoundError = py_mini_racer.LibNotFoundError
1013
MiniRacer = py_mini_racer.MiniRacer
1114
StrictMiniRacer = py_mini_racer.StrictMiniRacer
15+
init_mini_racer = py_mini_racer.init_mini_racer
1216

1317

1418
__all__ = ["py_mini_racer", "MiniRacer"]

src/py_mini_racer/py_mini_racer.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from os.path import join as pathjoin
1212
from sys import platform, version_info
1313
from threading import Lock
14-
from typing import ClassVar
14+
from typing import ClassVar, Iterable, Iterator
1515

1616

1717
class 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+
2837
class 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

135144
def _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

tests/test_init.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import pytest
2+
3+
from py_mini_racer import LibAlreadyInitializedError, init_mini_racer
4+
5+
6+
def test_init():
7+
init_mini_racer(ignore_duplicate_init=True)
8+
9+
with pytest.raises(LibAlreadyInitializedError):
10+
init_mini_racer()
11+
12+
init_mini_racer(ignore_duplicate_init=True)
13+
14+
15+
# Unfortunately while init_mini_racer allows changing V8 flags, it's hard to test
16+
# automatically because only the first use of V8 can set flags. We'd need to
17+
# restart Python between tests.
18+
# Here's a manual test:
19+
# def test_init_flags():
20+
# from py_mini_racer import DEFAULT_V8_FLAGS, MiniRacer, init_mini_racer
21+
# init_mini_racer(flags=(*DEFAULT_V8_FLAGS, '--no-use-strict'))
22+
# mr = MiniRacer()
23+
# # this would normally fail in strict JS mode because foo is not declared:
24+
# mr.eval('foo = 4')

0 commit comments

Comments
 (0)