Skip to content

Commit aa9fcd3

Browse files
committed
Add JSString
1 parent 48fee01 commit aa9fcd3

13 files changed

Lines changed: 77 additions & 30 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ respectively:
135135
[None, JSUndefined]
136136
```
137137

138+
JavaScript strings are represented as `JSString`, a subclass of `str` which enables them
139+
to be efficiently passed back to JavaScript:
140+
141+
```python
142+
>>> from py_mini_racer import JSString
143+
>>> assert isinstance(ctx.eval("'foo'"), JSString)
144+
```
145+
138146
You can prevent runaway execution in synchronous code using the `timeout_sec` parameter:
139147

140148
```python

src/py_mini_racer/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
JSMappedObject,
2525
JSObject,
2626
JSPromise,
27+
JSString,
2728
JSSymbol,
2829
JSUndefined,
2930
JSUndefinedType,
@@ -45,6 +46,7 @@
4546
"JSParseException",
4647
"JSPromise",
4748
"JSPromiseError",
49+
"JSString",
4850
"JSSymbol",
4951
"JSTimeoutException",
5052
"JSUndefined",

src/py_mini_racer/_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from typing import TYPE_CHECKING, Any, NewType, Protocol, cast
99

1010
from py_mini_racer._dll import init_mini_racer
11-
from py_mini_racer._exc import JSEvalException, JSPromiseError
11+
from py_mini_racer._exc import JSPromiseError
1212
from py_mini_racer._types import (
1313
CancelableJSFunction,
1414
JSArray,

src/py_mini_racer/_objects.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import ctypes
77
from datetime import datetime, timezone
88
from operator import index as op_index
9-
from typing import TYPE_CHECKING, Any, ClassVar, cast
9+
from typing import TYPE_CHECKING, Any, ClassVar, Self, cast
1010

1111
from py_mini_racer._exc import (
1212
JSArrayIndexError,
@@ -26,6 +26,7 @@
2626
JSMappedObject,
2727
JSObject,
2828
JSPromise,
29+
JSString,
2930
JSSymbol,
3031
JSUndefined,
3132
JSUndefinedType,
@@ -192,6 +193,16 @@ def __await__(self) -> Generator[Any, None, Any]:
192193
return self._ctx.await_promise(self).__await__()
193194

194195

196+
class JSStringImpl(JSObjectImpl, JSString):
197+
def __new__(cls, ctx: Context, handle: ValueHandle, content: str) -> Self:
198+
del ctx, handle
199+
return super().__new__(cls, content)
200+
201+
def __init__(self, ctx: Context, handle: ValueHandle, content: str) -> None:
202+
del content
203+
JSObjectImpl.__init__(self, ctx, handle)
204+
205+
195206
class _ArrayBufferByte(ctypes.Structure):
196207
# Cannot use c_ubyte directly because it uses <B
197208
# as an internal type but we need B for memoryview.
@@ -300,7 +311,9 @@ def value_handle_to_python( # noqa: C901, PLR0911, PLR0912
300311
if typ == _MiniRacerTypes.double:
301312
return float(val.double_val)
302313
if typ == _MiniRacerTypes.string:
303-
return str(val.bytes_val[0:length].decode("utf-8"))
314+
return JSStringImpl(
315+
ctx, val_handle, val.bytes_val[0:length].decode("utf-8")
316+
)
304317
if typ == _MiniRacerTypes.function:
305318
return JSFunctionImpl(ctx, val_handle)
306319
if typ == _MiniRacerTypes.date:

src/py_mini_racer/_types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ class JSObject:
3333
"""A JavaScript object."""
3434

3535

36+
class JSString(str, JSObject):
37+
__slots__ = ()
38+
39+
3640
class JSMappedObject(
3741
MutableMapping["PythonJSConvertedTypes", "PythonJSConvertedTypes"], JSObject
3842
):

src/v8_py_frontend/cancelable_task_runner.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ class CancelableTaskManager {
3939
~CancelableTaskManager();
4040

4141
CancelableTaskManager(const CancelableTaskManager&) = delete;
42-
auto operator=(const CancelableTaskManager&)
43-
-> CancelableTaskManager& = delete;
42+
auto operator=(const CancelableTaskManager&) -> CancelableTaskManager& =
43+
delete;
4444
CancelableTaskManager(CancelableTaskManager&&) = delete;
45-
auto operator=(CancelableTaskManager&& other)
46-
-> CancelableTaskManager& = delete;
45+
auto operator=(CancelableTaskManager&& other) -> CancelableTaskManager& =
46+
delete;
4747

4848
/**
4949
* Schedule the given runnable.

src/v8_py_frontend/context.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,8 @@ auto Context::GetOwnPropertyNames(ValueHandle* obj_handle) -> ValueHandle* {
138138
.get();
139139
}
140140

141-
auto Context::GetObjectItem(ValueHandle* obj_handle, ValueHandle* key_handle)
142-
-> ValueHandle* {
141+
auto Context::GetObjectItem(ValueHandle* obj_handle,
142+
ValueHandle* key_handle) -> ValueHandle* {
143143
return isolate_manager_
144144
.Schedule([this, obj_handle, key_handle]() mutable {
145145
auto obj_value = val_registry_.FromHandle(obj_handle);
@@ -184,8 +184,8 @@ auto Context::SetObjectItem(ValueHandle* obj_handle,
184184
.get();
185185
}
186186

187-
auto Context::DelObjectItem(ValueHandle* obj_handle, ValueHandle* key_handle)
188-
-> ValueHandle* {
187+
auto Context::DelObjectItem(ValueHandle* obj_handle,
188+
ValueHandle* key_handle) -> ValueHandle* {
189189
return isolate_manager_
190190
.Schedule([this, obj_handle, key_handle]() mutable {
191191
auto obj_value = val_registry_.FromHandle(obj_handle);
@@ -231,8 +231,8 @@ auto Context::SpliceArray(ValueHandle* obj_handle,
231231
.get();
232232
}
233233

234-
auto Context::ArrayPush(ValueHandle* obj_handle, ValueHandle* new_val_handle)
235-
-> ValueHandle* {
234+
auto Context::ArrayPush(ValueHandle* obj_handle,
235+
ValueHandle* new_val_handle) -> ValueHandle* {
236236
return isolate_manager_
237237
.Schedule([this, obj_handle, new_val_handle]() {
238238
auto obj_value = val_registry_.FromHandle(obj_handle);
@@ -271,8 +271,8 @@ auto Context::AllocDouble(double val, ValueTypes type) -> ValueHandle* {
271271
.get();
272272
}
273273

274-
auto Context::AllocString(std::string_view val, ValueTypes type)
275-
-> ValueHandle* {
274+
auto Context::AllocString(std::string_view val,
275+
ValueTypes type) -> ValueHandle* {
276276
return isolate_manager_
277277
.Schedule([this, val, type]() {
278278
return val_registry_.Remember(val_factory_.NewFromString(val, type));

src/v8_py_frontend/context.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,19 @@ class Context {
4949
auto MakeJSCallback(uint64_t callback_id) -> ValueHandle*;
5050
auto GetIdentityHash(ValueHandle* obj_handle) -> ValueHandle*;
5151
auto GetOwnPropertyNames(ValueHandle* obj_handle) -> ValueHandle*;
52-
auto GetObjectItem(ValueHandle* obj_handle, ValueHandle* key_handle)
53-
-> ValueHandle*;
52+
auto GetObjectItem(ValueHandle* obj_handle,
53+
ValueHandle* key_handle) -> ValueHandle*;
5454
auto SetObjectItem(ValueHandle* obj_handle,
5555
ValueHandle* key_handle,
5656
ValueHandle* val_handle) -> ValueHandle*;
57-
auto DelObjectItem(ValueHandle* obj_handle, ValueHandle* key_handle)
58-
-> ValueHandle*;
57+
auto DelObjectItem(ValueHandle* obj_handle,
58+
ValueHandle* key_handle) -> ValueHandle*;
5959
auto SpliceArray(ValueHandle* obj_handle,
6060
int32_t start,
6161
int32_t delete_count,
6262
ValueHandle* new_val_handle) -> ValueHandle*;
63-
auto ArrayPush(ValueHandle* obj_handle, ValueHandle* new_val_handle)
64-
-> ValueHandle*;
63+
auto ArrayPush(ValueHandle* obj_handle,
64+
ValueHandle* new_val_handle) -> ValueHandle*;
6565
auto CallFunction(ValueHandle* func_handle,
6666
ValueHandle* this_handle,
6767
ValueHandle* argv_handle,

src/v8_py_frontend/object_manipulator.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,9 @@ auto ObjectManipulator::Get(Value* obj_ptr, Value* key_ptr) -> Value::Ptr {
5959
return val_factory_->NewFromAny(value);
6060
}
6161

62-
auto ObjectManipulator::Set(Value* obj_ptr, Value* key_ptr, Value* val_ptr)
63-
-> Value::Ptr {
62+
auto ObjectManipulator::Set(Value* obj_ptr,
63+
Value* key_ptr,
64+
Value* val_ptr) -> Value::Ptr {
6465
v8::Isolate* isolate = isolate_manager_->GetIsolate();
6566

6667
const v8::Local<v8::Value> local_obj_val = obj_ptr->Global()->Get(isolate);
@@ -182,8 +183,9 @@ auto ObjectManipulator::Push(Value* obj_ptr, Value* new_val_ptr) -> Value::Ptr {
182183
return val_factory_->NewFromAny(maybe_value.ToLocalChecked());
183184
}
184185

185-
auto ObjectManipulator::Call(Value* func_ptr, Value* this_ptr, Value* argv_ptr)
186-
-> Value::Ptr {
186+
auto ObjectManipulator::Call(Value* func_ptr,
187+
Value* this_ptr,
188+
Value* argv_ptr) -> Value::Ptr {
187189
v8::Isolate* isolate = isolate_manager_->GetIsolate();
188190

189191
const v8::Local<v8::Value> local_func_val = func_ptr->Global()->Get(isolate);

src/v8_py_frontend/value.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ auto Value::GetHandle() -> ValueHandle* {
140140
ValueFactory::ValueFactory(IsolateManager* isolate_manager)
141141
: isolate_manager_(isolate_manager) {}
142142

143-
auto ValueFactory::New(v8::Local<v8::Value> value, ValueTypes type)
144-
-> Value::Ptr {
143+
auto ValueFactory::New(v8::Local<v8::Value> value,
144+
ValueTypes type) -> Value::Ptr {
145145
const v8::Local<v8::Context> context = isolate_manager_->GetLocalContext();
146146
return std::make_unique<Value>(isolate_manager_->GetIsolate(), context, value,
147147
type);
@@ -176,8 +176,8 @@ auto ValueFactory::NewFromDouble(double value, ValueTypes type) -> Value::Ptr {
176176
return New(v8::Number::New(isolate_manager_->GetIsolate(), value), type);
177177
}
178178

179-
auto ValueFactory::NewFromString(std::string_view message, ValueTypes type)
180-
-> Value::Ptr {
179+
auto ValueFactory::NewFromString(std::string_view message,
180+
ValueTypes type) -> Value::Ptr {
181181
return New(v8::String::NewFromUtf8(isolate_manager_->GetIsolate(),
182182
message.data(), v8::NewStringType::kNormal,
183183
static_cast<int>(message.size()))

0 commit comments

Comments
 (0)