bare-script 5.1.6__tar.gz → 5.1.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bare_script-5.1.6/src/bare_script.egg-info → bare_script-5.1.7}/PKG-INFO +12 -1
- {bare_script-5.1.6 → bare_script-5.1.7}/README.md +11 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/pyproject.toml +1 -1
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/runtime.py +25 -16
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/runtime_c.c +26 -2
- {bare_script-5.1.6 → bare_script-5.1.7/src/bare_script.egg-info}/PKG-INFO +12 -1
- {bare_script-5.1.6 → bare_script-5.1.7}/LICENSE +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/setup.cfg +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/setup.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/__init__.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/__main__.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/bare.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/include.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/include_source.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/library.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/options.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script/value.py +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script.egg-info/SOURCES.txt +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script.egg-info/dependency_links.txt +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script.egg-info/entry_points.txt +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script.egg-info/requires.txt +0 -0
- {bare_script-5.1.6 → bare_script-5.1.7}/src/bare_script.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bare-script
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.7
|
|
4
4
|
Summary: BareScript; a lightweight scripting and expression language
|
|
5
5
|
Author-email: "Craig A. Hobbs" <craigahobbs@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -296,6 +296,17 @@ builds. See the Performance section below for benchmark results comparing the C
|
|
|
296
296
|
pure-Python runtime, and native Python.
|
|
297
297
|
|
|
298
298
|
|
|
299
|
+
## Thread Safety
|
|
300
|
+
|
|
301
|
+
Both runtimes may be used from multiple threads, including on the free-threaded (no-GIL) Python
|
|
302
|
+
builds. Script models and a `globals` dict may be shared across threads once populated - for example,
|
|
303
|
+
execute a script that defines functions once, then call those functions concurrently. Each
|
|
304
|
+
concurrently executing thread must pass its own `options` dict to `execute_script`, since the runtime
|
|
305
|
+
records the running `statementCount` there. The parser, linter, and include library stubs initialize
|
|
306
|
+
lazily and are safe to call from any thread. As in Python, unsynchronized concurrent mutation of a
|
|
307
|
+
shared array or object from several threads has unspecified results but never crashes the runtime.
|
|
308
|
+
|
|
309
|
+
|
|
299
310
|
## Performance
|
|
300
311
|
|
|
301
312
|
The `make perf` target benchmarks the BareScript runtime with a suite of compute-intensive tests —
|
|
@@ -270,6 +270,17 @@ builds. See the Performance section below for benchmark results comparing the C
|
|
|
270
270
|
pure-Python runtime, and native Python.
|
|
271
271
|
|
|
272
272
|
|
|
273
|
+
## Thread Safety
|
|
274
|
+
|
|
275
|
+
Both runtimes may be used from multiple threads, including on the free-threaded (no-GIL) Python
|
|
276
|
+
builds. Script models and a `globals` dict may be shared across threads once populated - for example,
|
|
277
|
+
execute a script that defines functions once, then call those functions concurrently. Each
|
|
278
|
+
concurrently executing thread must pass its own `options` dict to `execute_script`, since the runtime
|
|
279
|
+
records the running `statementCount` there. The parser, linter, and include library stubs initialize
|
|
280
|
+
lazily and are safe to call from any thread. As in Python, unsynchronized concurrent mutation of a
|
|
281
|
+
shared array or object from several threads has unspecified results but never crashes the runtime.
|
|
282
|
+
|
|
283
|
+
|
|
273
284
|
## Performance
|
|
274
285
|
|
|
275
286
|
The `make perf` target benchmarks the BareScript runtime with a suite of compute-intensive tests —
|
|
@@ -10,6 +10,7 @@ import functools
|
|
|
10
10
|
import json
|
|
11
11
|
import math
|
|
12
12
|
import sys
|
|
13
|
+
import threading
|
|
13
14
|
|
|
14
15
|
from .include_source import SYSTEM_INCLUDES
|
|
15
16
|
from .library import EXPRESSION_FUNCTIONS, INTRINSICS, SCRIPT_FUNCTIONS
|
|
@@ -199,20 +200,25 @@ def _execute_script_helper(script, statements, options, locals_, label_indexes):
|
|
|
199
200
|
return None
|
|
200
201
|
|
|
201
202
|
|
|
202
|
-
# The barescriptParser.bare include library script globals (lazily initialized)
|
|
203
|
+
# The barescriptParser.bare include library script globals (lazily initialized under a lock)
|
|
203
204
|
_PARSER_GLOBALS = None
|
|
205
|
+
_PARSER_GLOBALS_INIT_LOCK = threading.Lock()
|
|
204
206
|
|
|
205
207
|
|
|
206
208
|
def _parser_globals_init():
|
|
207
|
-
# Execute the barescriptParser.bare include library script, if necessary
|
|
209
|
+
# Execute the barescriptParser.bare include library script, if necessary. The globals are built
|
|
210
|
+
# locally and published only once complete so a concurrent first-use caller never observes a
|
|
211
|
+
# partially-initialized parser; the lock serializes the one-time initialization.
|
|
208
212
|
# pylint: disable-next=global-statement
|
|
209
213
|
global _PARSER_GLOBALS
|
|
210
|
-
|
|
211
|
-
_PARSER_GLOBALS
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
with _PARSER_GLOBALS_INIT_LOCK:
|
|
215
|
+
if _PARSER_GLOBALS is None:
|
|
216
|
+
parser_globals = {}
|
|
217
|
+
execute_script(
|
|
218
|
+
{'statements': [{'include': {'includes': [{'url': 'barescriptParser.bare', 'system': True}]}}]},
|
|
219
|
+
{'globals': parser_globals}
|
|
220
|
+
)
|
|
221
|
+
_PARSER_GLOBALS = parser_globals
|
|
216
222
|
|
|
217
223
|
|
|
218
224
|
def _normalize_statements(statements):
|
|
@@ -281,8 +287,9 @@ def barescript_parse_expression(expr_text, line_number=None, script_name=None, a
|
|
|
281
287
|
return result['result']
|
|
282
288
|
|
|
283
289
|
|
|
284
|
-
# The barescriptLint.bare include library script globals (lazily initialized)
|
|
290
|
+
# The barescriptLint.bare include library script globals (lazily initialized under a lock)
|
|
285
291
|
_LINT_GLOBALS = None
|
|
292
|
+
_LINT_GLOBALS_INIT_LOCK = threading.Lock()
|
|
286
293
|
|
|
287
294
|
|
|
288
295
|
def barescript_lint_script(script, globals_=None):
|
|
@@ -297,15 +304,17 @@ def barescript_lint_script(script, globals_=None):
|
|
|
297
304
|
:rtype: list[str]
|
|
298
305
|
"""
|
|
299
306
|
|
|
300
|
-
# Execute the barescriptLint.bare include library script, if necessary
|
|
307
|
+
# Execute the barescriptLint.bare include library script, if necessary (see _parser_globals_init)
|
|
301
308
|
# pylint: disable-next=global-statement
|
|
302
309
|
global _LINT_GLOBALS
|
|
303
|
-
|
|
304
|
-
_LINT_GLOBALS
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
310
|
+
with _LINT_GLOBALS_INIT_LOCK:
|
|
311
|
+
if _LINT_GLOBALS is None:
|
|
312
|
+
lint_globals = {}
|
|
313
|
+
execute_script(
|
|
314
|
+
{'statements': [{'include': {'includes': [{'url': 'barescriptLint.bare', 'system': True}]}}]},
|
|
315
|
+
{'globals': lint_globals}
|
|
316
|
+
)
|
|
317
|
+
_LINT_GLOBALS = lint_globals
|
|
309
318
|
|
|
310
319
|
# Call the barescriptLint.bare lint function. Async function detection is not possible in
|
|
311
320
|
# Python (all functions execute synchronously), so the async lint checks are skipped.
|
|
@@ -187,6 +187,7 @@ typedef struct {
|
|
|
187
187
|
PyObject *str_method_upper;
|
|
188
188
|
PyObject *str_method_lower;
|
|
189
189
|
PyObject *str_method_strip;
|
|
190
|
+
PyObject *str_method_pop;
|
|
190
191
|
|
|
191
192
|
// Imported objects
|
|
192
193
|
PyObject *script_functions;
|
|
@@ -783,7 +784,12 @@ static UnaryOp parse_unary_op(PyObject *op)
|
|
|
783
784
|
// value.value_args_validate model exactly and raise errors by calling the Python ValueArgsError
|
|
784
785
|
// class so messages and error return values match. Intrinsics never touch the options object, so
|
|
785
786
|
// no statement-counter sync is required around them. The table is populated once at module exec
|
|
786
|
-
// and immutable afterwards (free-threading safe).
|
|
787
|
+
// and immutable afterwards (free-threading safe). A per-call args list is private to the calling
|
|
788
|
+
// thread, but the arrays and objects it references may be shared with other threads, so handlers
|
|
789
|
+
// touch those only through the bounds-checked, locking list/dict APIs (list_get_ref,
|
|
790
|
+
// PyList_SetItem, list.pop, dict_get_ref, ...) under the free-threaded build, where an
|
|
791
|
+
// unsynchronized concurrent mutation then raises instead of reading freed storage. The default
|
|
792
|
+
// (GIL) build keeps the direct macro accessors - the GIL already serializes those operations.
|
|
787
793
|
//
|
|
788
794
|
|
|
789
795
|
|
|
@@ -1083,7 +1089,17 @@ static PyObject *intrinsic_array_get(PyObject *args)
|
|
|
1083
1089
|
intrinsic_index_bounds_error(args, 1, "index");
|
|
1084
1090
|
return NULL;
|
|
1085
1091
|
}
|
|
1092
|
+
#ifdef Py_GIL_DISABLED
|
|
1093
|
+
// Bounds-checked under the list's lock - an unsynchronized concurrent shrink by another thread
|
|
1094
|
+
// raises IndexError instead of reading freed storage
|
|
1095
|
+
PyObject *value;
|
|
1096
|
+
if (list_get_ref(array, index, &value) < 0) {
|
|
1097
|
+
return NULL;
|
|
1098
|
+
}
|
|
1099
|
+
return value;
|
|
1100
|
+
#else
|
|
1086
1101
|
return Py_NewRef(PyList_GET_ITEM(array, index));
|
|
1102
|
+
#endif
|
|
1087
1103
|
}
|
|
1088
1104
|
|
|
1089
1105
|
|
|
@@ -1150,12 +1166,19 @@ static PyObject *intrinsic_array_pop(PyObject *args)
|
|
|
1150
1166
|
intrinsic_args_error("array", array, NULL);
|
|
1151
1167
|
return NULL;
|
|
1152
1168
|
}
|
|
1169
|
+
#ifdef Py_GIL_DISABLED
|
|
1170
|
+
// list.pop() is atomic under the list's lock, like the reference implementation's array.pop() -
|
|
1171
|
+
// an unsynchronized concurrent pop by another thread then raises IndexError (empty list) rather
|
|
1172
|
+
// than returning an element this call did not remove
|
|
1173
|
+
return PyObject_CallMethodNoArgs(array, g.str_method_pop);
|
|
1174
|
+
#else
|
|
1153
1175
|
PyObject *value = Py_NewRef(PyList_GET_ITEM(array, length - 1));
|
|
1154
1176
|
if (PyList_SetSlice(array, length - 1, length, NULL) < 0) {
|
|
1155
1177
|
Py_DECREF(value);
|
|
1156
1178
|
return NULL;
|
|
1157
1179
|
}
|
|
1158
1180
|
return value;
|
|
1181
|
+
#endif
|
|
1159
1182
|
}
|
|
1160
1183
|
|
|
1161
1184
|
|
|
@@ -5223,7 +5246,8 @@ static int runtime_c_exec(PyObject *module)
|
|
|
5223
5246
|
intern_string(&g.str_copy, "copy") < 0 ||
|
|
5224
5247
|
intern_string(&g.str_method_upper, "upper") < 0 ||
|
|
5225
5248
|
intern_string(&g.str_method_lower, "lower") < 0 ||
|
|
5226
|
-
intern_string(&g.str_method_strip, "strip") < 0
|
|
5249
|
+
intern_string(&g.str_method_strip, "strip") < 0 ||
|
|
5250
|
+
intern_string(&g.str_method_pop, "pop") < 0) {
|
|
5227
5251
|
return -1;
|
|
5228
5252
|
}
|
|
5229
5253
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bare-script
|
|
3
|
-
Version: 5.1.
|
|
3
|
+
Version: 5.1.7
|
|
4
4
|
Summary: BareScript; a lightweight scripting and expression language
|
|
5
5
|
Author-email: "Craig A. Hobbs" <craigahobbs@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -296,6 +296,17 @@ builds. See the Performance section below for benchmark results comparing the C
|
|
|
296
296
|
pure-Python runtime, and native Python.
|
|
297
297
|
|
|
298
298
|
|
|
299
|
+
## Thread Safety
|
|
300
|
+
|
|
301
|
+
Both runtimes may be used from multiple threads, including on the free-threaded (no-GIL) Python
|
|
302
|
+
builds. Script models and a `globals` dict may be shared across threads once populated - for example,
|
|
303
|
+
execute a script that defines functions once, then call those functions concurrently. Each
|
|
304
|
+
concurrently executing thread must pass its own `options` dict to `execute_script`, since the runtime
|
|
305
|
+
records the running `statementCount` there. The parser, linter, and include library stubs initialize
|
|
306
|
+
lazily and are safe to call from any thread. As in Python, unsynchronized concurrent mutation of a
|
|
307
|
+
shared array or object from several threads has unspecified results but never crashes the runtime.
|
|
308
|
+
|
|
309
|
+
|
|
299
310
|
## Performance
|
|
300
311
|
|
|
301
312
|
The `make perf` target benchmarks the BareScript runtime with a suite of compute-intensive tests —
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|