pythonista-jscore-runtime 0.0.1__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 M4nw3l
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,266 @@
1
+ Metadata-Version: 2.4
2
+ Name: pythonista-jscore-runtime
3
+ Version: 0.0.1
4
+ Summary: Pythonista JSCore Runtime Framework - Execute JavaScript and WebAssembly with seamless interop support natively in Pythonista 3.
5
+ Author-email: M4nw3l <63550247+M4nw3l@users.noreply.github.com>
6
+ Requires-Python: >= 3.10
7
+ Description-Content-Type: text/markdown
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: iOS
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
14
+ Classifier: Topic :: Software Development :: Libraries
15
+ License-File: LICENSE
16
+ Project-URL: Homepage, https://github.com/M4nw3l/pythonista-jscore-runtime
17
+
18
+ # pythonista-jscore-runtime
19
+ ## JSCore Runtime Framework - Execute JavaScript and WebAssembly in Pythonista 3 natively on iOS with JavaScriptCore.
20
+ JSCore Runtime Framework is an experiment in pushing the boundaries of the Python environment and language features in the Pythonista 3 IDE and apps developed with it on iOS. It is an extensive Python 3 mapping of the JavaScriptCore Objective-C and C-APIs via objc-util. Implementing closely analogous Python integrations, wrapping and interop for evaluating JavaScript and WebAssembly in independent and composable JavaScriptCore execution environments from Python 3 applications and scripts. Focused also from a point of view of being a serious attempt to extend vanilla Pythonista 3 to ultimately support Python packages and modules with compiled extensions that can be cross-compiled reliably into WebAssembly.
21
+
22
+ The projects overall long term goals aim to offer three core capabilities/features:
23
+ - Evaluate/execute JavaScript and WebAssembly with seamless Python interop as a standalone library for Pythonista 3 based Python 3 apps.
24
+ - Compile, bundle, import and run custom source code and third party components extensibly with WebAssembly and JavaScript.
25
+ - Support Python packages/modules with extensions which can be cross-compiled to WebAssmembly from languages such as C.
26
+
27
+ A (very) simple example:
28
+ ```python
29
+
30
+ from jscore_runtime import *
31
+
32
+ with (jscore.runtime() as runtime, runtime.context() as context):
33
+ context.eval('function hello_world () { return "hello world"; }')
34
+ print(context.js.hello_world())
35
+ context.js.value_from_python = ["hello", "from", "python", 1, 2.2, 3.333333, {"object":"value", "nested":{"obj":["array", [], {}]}}]
36
+ print(context.eval('value_from_python[2] = "javascript"; value_from_python;').value)
37
+
38
+ # output:
39
+ # hello world
40
+ # ['hello', 'from', 'javascript', 1, 2.2, 3.333333, {'object': 'value', 'nested': {'obj': ['array', [], {}]}}]
41
+
42
+ ```
43
+
44
+ ## Installation
45
+
46
+ Download [jscore_runtime.py](jscore_runtime.py) from the repository and copy to your site-packages folder.
47
+
48
+ <!--
49
+ Install with pip via StaSh
50
+
51
+ ```bash
52
+ pip install pythonista-jscore-runtime
53
+ ```
54
+ -->
55
+
56
+ ## Usage
57
+ ### Javascript Runtime
58
+ JSCore Runtime supports both the context management and explicit create/destroy usage paradigms.
59
+ Alongside also automatically managed (singleton) quick/convenience evaluation and more explicit/multiple virtual machine and contexts instancing for advanced control.
60
+
61
+ A runtime singleton can be obtained from the `jscore` static class.
62
+ ```python
63
+ runtime = jscore.runtime()
64
+ ```
65
+ By default if no runtime class is specified a `javascript_runtime` with a virtal machine lifetime of the program is returned.
66
+
67
+ A runtime class can also be instantiated independently. On creation it will contain a pointer to its own independent JSVirtualMachine instance.
68
+ ```python
69
+ runtime = javascript_runtime()
70
+ ```
71
+
72
+ A context is required to evaluate code. A context instance is onbtained from an existing runtime instance:
73
+ ```python
74
+ context = runtime.context()
75
+ ```
76
+ The context type matches the runtime type. e.g `javascript_runtime` returns `javascript_context` instances. Similarly to runtimes, contexts are independent of one another such that the state of one context is distinct to and isolated from another unless it is explictly configured for sharing via context groups.
77
+
78
+ A context may evaluate javascript with several javascript evaluation function variants:
79
+ ```python
80
+ # general purpose javascript string evaluation function
81
+ context.eval(jsSourceCode)
82
+ # returns:
83
+ # eval_result {"value": [python js value representation] or None , "exception": exception string or None }
84
+
85
+ # module loader based javascript evaluation functions
86
+ # regular javascript scripts/programs loaded synchronously
87
+ context.eval_source(jsSourceCode)
88
+ context.eval_file(".path/to/js-file.js")
89
+
90
+ # javascript modules loaded asynchronously
91
+ context.eval_module_source(moduleSourceCode, './optional/path/to/virtal-name.js')
92
+ context.eval_module_file("./path/to/module/index.js")
93
+
94
+ # all return:
95
+ # eval_result {"value": [python js value representation] or None , "exception": exception string or None }
96
+ ```
97
+
98
+ ### context.js accessor
99
+ A `javascript_context` provides a `js` property which allows access to the javascript contexts global object in a 'python-esque' interface.
100
+ Most simple python values may be retrieved and set through this accessor. It follows JavaScript access rules, and cannot subvert them, e.g. setting a const value fails with an exception. All read/write variables may otherwise be set and manipulated.
101
+
102
+ ```python
103
+ context.js.number = 10
104
+ context.js.double = 1.1
105
+ context.js.array = []
106
+ context.js.object = {}
107
+ ```
108
+
109
+ Python functions can be specified as functions callable from javascript:
110
+
111
+ ```python
112
+
113
+ def python_print(text):
114
+ print(text)
115
+
116
+ context.js.python_print = python_print
117
+
118
+ # call from javascript
119
+ context.eval('python_print("hello from javascript");')
120
+ # call from python as javascript_function calling back to python
121
+ context.js.python_print("hello via javascript")
122
+
123
+ # any callable may be specified
124
+ context.js.python_fn = lambda text: print(text)
125
+
126
+ # values can be returned to javascript
127
+ context.js.python_val = lambda: {"str": "Hello from python", "num":10, "list":[1,2,3]}
128
+ # and back to python
129
+ context.eval('python_print(python_val());')
130
+ ```
131
+
132
+ A function may also be created with javascript source:
133
+ ```python
134
+ context.js.my_function = javascript_function.from_source('function() { return 1234; }')
135
+ ```
136
+ Defined javascript functions may also be called directly from Python:
137
+ ```python
138
+ context.js.my_function() # returns 1234
139
+ ```
140
+
141
+ ### WebAssembly Runtime
142
+ The `wasm_runtime` class, and its associated `wasm_context` and `wasm_module` classes allow WebAssembly modules to be loaded
143
+ with files and byte arrays from Python. They efficiently load WebAssembly modules via a direct buffer copy of an NSData objects bytes into a Uint8Arrays backing store in JavaScriptCore. Allowing a module and its instance to then instantiated, and its exports are bridged directly to Python. Interop with JavaScriptCore allows WebAssembly functions to be mapped and called as any other normal Python callable function. WebAssembly methods are exposed from JavaScriptCore as `function() { [Native Code] }` bodied functions. The performance should be close to excuting code natively but is still being interpreted by JavaScriptCore. It is also likely that JavaScriptCore's WebAssembly runtime may be subject to some restrictions imposed by Apple's general security policies.
144
+
145
+ To create a `wasm_context` to instantiate `wasm_module` instances from a `wasm_runtime` instance needs to be created first. This currently works the same way as the `javascript_runtime`.
146
+
147
+ A singleton runtime instance, with a lifetime of the program, may be obtained from the `jscore.runtime` accessor.
148
+ ```python
149
+ runtime = jscore.runtime(wasm_runtime)
150
+ ```
151
+
152
+ Alternatively a `wasm_runtime` instance may also be created and managed independently. Similarly to the `javascript_runtime` it will contain a pointer to a separate JSVirtualMachine instance.
153
+
154
+ ```python
155
+ runtime = wasm_runtime()
156
+ ```
157
+
158
+ A `wasm_context` may be obtained from runtime instance:
159
+
160
+ ```python
161
+ context = runtime.context()
162
+ ```
163
+
164
+ Although a `wasm_context` may execute JavaScript and vice versa, `wasm_runtime` and `wasm_context` are designed to integrate Python with WebAssembly as a first class runtime, without need for any JavaScript by default, to load and call WebAssembly modules from Python.
165
+
166
+ WebAssembly modules can be loaded from files or as raw bytes with the `wasm_module` class and `wasm_context.load_module` function.
167
+
168
+ ```python
169
+ module_file = wasm_module.from_file("./path/to/module.wasm")
170
+ module_bytes = wasm_module(b'\0asm\1\0\0\0'+b'[module_body_bytes]', 'optional_module_name_or_path')
171
+ module_data = wasm_module([0, 97, 115, 109, 1, 0, 0, 0, ...], 'optional_module_name_or_path')
172
+
173
+ module_instance = module_file
174
+ context.load_module(module_instance)
175
+
176
+ # once a module has been loaded its instance and exports are available from properties
177
+ print(module_instance.instance)
178
+ print(module_instance.exports)
179
+
180
+ ```
181
+ Imports may be specified before loading a `wasm_module` instance obtained from a files or bytes into the context.
182
+ Python functions may be specified as imports directly, they will be converted automatically into a `javascript_callback` instance.
183
+
184
+ ```python
185
+ module = wasm_module.from_file("./path/to/module.wasm")
186
+ # define python functions for imports
187
+ def imported_func(arg):
188
+ pass
189
+ module.imports.my_namespace.imported_func = imported_func
190
+
191
+ # any callable may be specified as an import, the only requirement is parameters counts match.
192
+ module.imports.my_namespace.imported_func = lambda v: print(v)
193
+
194
+ # a javascript_function may also be specified as an import
195
+ module.imports.my_namespace.imported_func = javascript_function.from_source("function (arg) { }")
196
+
197
+ # an ImportError is raised if load_module is called for modules expecting imports without functions
198
+ # for all of the expected imports specified.
199
+ context.load_module(module)
200
+
201
+ ```
202
+
203
+ Previously loaded module instances may be retrieved from the context:
204
+ ```python
205
+ loaded_modules = context.modules # all modules
206
+
207
+ loaded_module = context.module("module_name_or_path")
208
+ ```
209
+
210
+ WebAssembly exported functions are invoked as a regular Python function using an underlying `javascript_function` instance.
211
+
212
+ ```python
213
+ module = wasm_module.from_file("./path/to/module.wasm")
214
+ context.load(module)
215
+
216
+ module.exports.exported_function()
217
+ module.exports.exported_function_with_parameters(convertible, python, args)
218
+ ```
219
+ The following function is currently acting as the module loader on JavaScriptCore's side, it is defined in the context by `wasm_context` upon its allocation.
220
+
221
+ ```javascript
222
+ const _jscore_wasm_modules = {}
223
+ function _jscore_wasm_load(name, wasm_bin, namespace){
224
+ if(namespace === null) { namespace = {}; }
225
+ const wasm_module = new WebAssembly.Module(wasm_bin);
226
+ const wasm_instance = new WebAssembly.Instance(wasm_module, namespace);
227
+ const wasm_module_instance = {"instance": wasm_instance, "namespace": namespace, "module": wasm_module};
228
+ _jscore_wasm_modules[name] = wasm_module_instance; // ensure module remains in scope
229
+ return wasm_module_instance;
230
+ }
231
+ ```
232
+ Calling `wasm_context.load_module` will call this function to create `WebAssembly.Module` and `WebAssebly.Instance` instances in JavaScript with a WebAssembly binary passed as an `Uint8Array` typed array instance and an imports namespace.
233
+
234
+ #### Example: Loading and calling Mozilla's simple.wasm
235
+ An end to end example of loading and using a WebAssembly from Pythonista can be demonstrated by replicating [Mozilla's Loading Wasm Modules in Javascript](https://developer.mozilla.org/en-US/docs/WebAssembly/Guides/Using_the_JavaScript_API#loading_wasm_modules_in_javascript) example.
236
+
237
+ - Firstly, download the [simple.wasm](https://raw.githubusercontent.com/mdn/webassembly-examples/master/js-api-examples/simple.wasm) module from the page.
238
+ - After downloading simple.wasm, the next step is to copy this into Pythonista. To do this, navigate to the simple.wasm file in your Files app, then select the file and open the sharing sheet, then tap "Run Pythonista Script" and then choose the "Import File" option.
239
+ - **Note: This is the only safe way to import .wasm files into Pythonista. The import function from in the Pythonista app itself does not support .wasm files and must not be used to import binary!**
240
+ - Create a folder for your project and copy simple.wasm inside.
241
+ - In your folder with the simple.wasm module create the following script:
242
+
243
+ ```python
244
+
245
+ from jscore_runtime import *
246
+ with (jscore.runtime(wasm_runtime) as runtime, runtime.context() as context):
247
+ # load module file
248
+ module = wasm_module.from_file('./simple.wasm')
249
+ # define imports
250
+ module.imports.my_namespace.imported_func = lambda v: print(v)
251
+ # load module into context
252
+ context.load_module(module)
253
+ # once loaded, a modules exports become available and may be invoked
254
+ module.exports.exported_func() # prints 42
255
+
256
+ # output: 42
257
+ ```
258
+ Modules loading has been made to closely align with javascript with a couple of notable differences, firstly Python functions/callables may be used as imports as well as javascript functions. A fixed imports table is defined per `wasm_module` and `wasm_context`, imports must therefore be specified via the `wasm_module.imports` module specific imports or `wasm_context.imports` context-wide imports properties. A modules imports always override context-wide imports.
259
+
260
+ ## Known issues
261
+ - Loading javascript files from remote sources / cdns etc is not implemented (yet).
262
+ - Modules and scripts loading may not work correctly for some javascript libraries and they may need manual adjustments to work currently.
263
+ - ModulesLoaderDelegate is using a private protcol / api as there is no other way to access the functionality otherwise.
264
+ - JSScript source code strings are C++ objects which are more awkward structures to read with ctypes. A work around of separately loading a copy of the script source is used at the moment, so any module preprocessing performed when loading a JSScript is lost currently.
265
+
266
+
@@ -0,0 +1,248 @@
1
+ # pythonista-jscore-runtime
2
+ ## JSCore Runtime Framework - Execute JavaScript and WebAssembly in Pythonista 3 natively on iOS with JavaScriptCore.
3
+ JSCore Runtime Framework is an experiment in pushing the boundaries of the Python environment and language features in the Pythonista 3 IDE and apps developed with it on iOS. It is an extensive Python 3 mapping of the JavaScriptCore Objective-C and C-APIs via objc-util. Implementing closely analogous Python integrations, wrapping and interop for evaluating JavaScript and WebAssembly in independent and composable JavaScriptCore execution environments from Python 3 applications and scripts. Focused also from a point of view of being a serious attempt to extend vanilla Pythonista 3 to ultimately support Python packages and modules with compiled extensions that can be cross-compiled reliably into WebAssembly.
4
+
5
+ The projects overall long term goals aim to offer three core capabilities/features:
6
+ - Evaluate/execute JavaScript and WebAssembly with seamless Python interop as a standalone library for Pythonista 3 based Python 3 apps.
7
+ - Compile, bundle, import and run custom source code and third party components extensibly with WebAssembly and JavaScript.
8
+ - Support Python packages/modules with extensions which can be cross-compiled to WebAssmembly from languages such as C.
9
+
10
+ A (very) simple example:
11
+ ```python
12
+
13
+ from jscore_runtime import *
14
+
15
+ with (jscore.runtime() as runtime, runtime.context() as context):
16
+ context.eval('function hello_world () { return "hello world"; }')
17
+ print(context.js.hello_world())
18
+ context.js.value_from_python = ["hello", "from", "python", 1, 2.2, 3.333333, {"object":"value", "nested":{"obj":["array", [], {}]}}]
19
+ print(context.eval('value_from_python[2] = "javascript"; value_from_python;').value)
20
+
21
+ # output:
22
+ # hello world
23
+ # ['hello', 'from', 'javascript', 1, 2.2, 3.333333, {'object': 'value', 'nested': {'obj': ['array', [], {}]}}]
24
+
25
+ ```
26
+
27
+ ## Installation
28
+
29
+ Download [jscore_runtime.py](jscore_runtime.py) from the repository and copy to your site-packages folder.
30
+
31
+ <!--
32
+ Install with pip via StaSh
33
+
34
+ ```bash
35
+ pip install pythonista-jscore-runtime
36
+ ```
37
+ -->
38
+
39
+ ## Usage
40
+ ### Javascript Runtime
41
+ JSCore Runtime supports both the context management and explicit create/destroy usage paradigms.
42
+ Alongside also automatically managed (singleton) quick/convenience evaluation and more explicit/multiple virtual machine and contexts instancing for advanced control.
43
+
44
+ A runtime singleton can be obtained from the `jscore` static class.
45
+ ```python
46
+ runtime = jscore.runtime()
47
+ ```
48
+ By default if no runtime class is specified a `javascript_runtime` with a virtal machine lifetime of the program is returned.
49
+
50
+ A runtime class can also be instantiated independently. On creation it will contain a pointer to its own independent JSVirtualMachine instance.
51
+ ```python
52
+ runtime = javascript_runtime()
53
+ ```
54
+
55
+ A context is required to evaluate code. A context instance is onbtained from an existing runtime instance:
56
+ ```python
57
+ context = runtime.context()
58
+ ```
59
+ The context type matches the runtime type. e.g `javascript_runtime` returns `javascript_context` instances. Similarly to runtimes, contexts are independent of one another such that the state of one context is distinct to and isolated from another unless it is explictly configured for sharing via context groups.
60
+
61
+ A context may evaluate javascript with several javascript evaluation function variants:
62
+ ```python
63
+ # general purpose javascript string evaluation function
64
+ context.eval(jsSourceCode)
65
+ # returns:
66
+ # eval_result {"value": [python js value representation] or None , "exception": exception string or None }
67
+
68
+ # module loader based javascript evaluation functions
69
+ # regular javascript scripts/programs loaded synchronously
70
+ context.eval_source(jsSourceCode)
71
+ context.eval_file(".path/to/js-file.js")
72
+
73
+ # javascript modules loaded asynchronously
74
+ context.eval_module_source(moduleSourceCode, './optional/path/to/virtal-name.js')
75
+ context.eval_module_file("./path/to/module/index.js")
76
+
77
+ # all return:
78
+ # eval_result {"value": [python js value representation] or None , "exception": exception string or None }
79
+ ```
80
+
81
+ ### context.js accessor
82
+ A `javascript_context` provides a `js` property which allows access to the javascript contexts global object in a 'python-esque' interface.
83
+ Most simple python values may be retrieved and set through this accessor. It follows JavaScript access rules, and cannot subvert them, e.g. setting a const value fails with an exception. All read/write variables may otherwise be set and manipulated.
84
+
85
+ ```python
86
+ context.js.number = 10
87
+ context.js.double = 1.1
88
+ context.js.array = []
89
+ context.js.object = {}
90
+ ```
91
+
92
+ Python functions can be specified as functions callable from javascript:
93
+
94
+ ```python
95
+
96
+ def python_print(text):
97
+ print(text)
98
+
99
+ context.js.python_print = python_print
100
+
101
+ # call from javascript
102
+ context.eval('python_print("hello from javascript");')
103
+ # call from python as javascript_function calling back to python
104
+ context.js.python_print("hello via javascript")
105
+
106
+ # any callable may be specified
107
+ context.js.python_fn = lambda text: print(text)
108
+
109
+ # values can be returned to javascript
110
+ context.js.python_val = lambda: {"str": "Hello from python", "num":10, "list":[1,2,3]}
111
+ # and back to python
112
+ context.eval('python_print(python_val());')
113
+ ```
114
+
115
+ A function may also be created with javascript source:
116
+ ```python
117
+ context.js.my_function = javascript_function.from_source('function() { return 1234; }')
118
+ ```
119
+ Defined javascript functions may also be called directly from Python:
120
+ ```python
121
+ context.js.my_function() # returns 1234
122
+ ```
123
+
124
+ ### WebAssembly Runtime
125
+ The `wasm_runtime` class, and its associated `wasm_context` and `wasm_module` classes allow WebAssembly modules to be loaded
126
+ with files and byte arrays from Python. They efficiently load WebAssembly modules via a direct buffer copy of an NSData objects bytes into a Uint8Arrays backing store in JavaScriptCore. Allowing a module and its instance to then instantiated, and its exports are bridged directly to Python. Interop with JavaScriptCore allows WebAssembly functions to be mapped and called as any other normal Python callable function. WebAssembly methods are exposed from JavaScriptCore as `function() { [Native Code] }` bodied functions. The performance should be close to excuting code natively but is still being interpreted by JavaScriptCore. It is also likely that JavaScriptCore's WebAssembly runtime may be subject to some restrictions imposed by Apple's general security policies.
127
+
128
+ To create a `wasm_context` to instantiate `wasm_module` instances from a `wasm_runtime` instance needs to be created first. This currently works the same way as the `javascript_runtime`.
129
+
130
+ A singleton runtime instance, with a lifetime of the program, may be obtained from the `jscore.runtime` accessor.
131
+ ```python
132
+ runtime = jscore.runtime(wasm_runtime)
133
+ ```
134
+
135
+ Alternatively a `wasm_runtime` instance may also be created and managed independently. Similarly to the `javascript_runtime` it will contain a pointer to a separate JSVirtualMachine instance.
136
+
137
+ ```python
138
+ runtime = wasm_runtime()
139
+ ```
140
+
141
+ A `wasm_context` may be obtained from runtime instance:
142
+
143
+ ```python
144
+ context = runtime.context()
145
+ ```
146
+
147
+ Although a `wasm_context` may execute JavaScript and vice versa, `wasm_runtime` and `wasm_context` are designed to integrate Python with WebAssembly as a first class runtime, without need for any JavaScript by default, to load and call WebAssembly modules from Python.
148
+
149
+ WebAssembly modules can be loaded from files or as raw bytes with the `wasm_module` class and `wasm_context.load_module` function.
150
+
151
+ ```python
152
+ module_file = wasm_module.from_file("./path/to/module.wasm")
153
+ module_bytes = wasm_module(b'\0asm\1\0\0\0'+b'[module_body_bytes]', 'optional_module_name_or_path')
154
+ module_data = wasm_module([0, 97, 115, 109, 1, 0, 0, 0, ...], 'optional_module_name_or_path')
155
+
156
+ module_instance = module_file
157
+ context.load_module(module_instance)
158
+
159
+ # once a module has been loaded its instance and exports are available from properties
160
+ print(module_instance.instance)
161
+ print(module_instance.exports)
162
+
163
+ ```
164
+ Imports may be specified before loading a `wasm_module` instance obtained from a files or bytes into the context.
165
+ Python functions may be specified as imports directly, they will be converted automatically into a `javascript_callback` instance.
166
+
167
+ ```python
168
+ module = wasm_module.from_file("./path/to/module.wasm")
169
+ # define python functions for imports
170
+ def imported_func(arg):
171
+ pass
172
+ module.imports.my_namespace.imported_func = imported_func
173
+
174
+ # any callable may be specified as an import, the only requirement is parameters counts match.
175
+ module.imports.my_namespace.imported_func = lambda v: print(v)
176
+
177
+ # a javascript_function may also be specified as an import
178
+ module.imports.my_namespace.imported_func = javascript_function.from_source("function (arg) { }")
179
+
180
+ # an ImportError is raised if load_module is called for modules expecting imports without functions
181
+ # for all of the expected imports specified.
182
+ context.load_module(module)
183
+
184
+ ```
185
+
186
+ Previously loaded module instances may be retrieved from the context:
187
+ ```python
188
+ loaded_modules = context.modules # all modules
189
+
190
+ loaded_module = context.module("module_name_or_path")
191
+ ```
192
+
193
+ WebAssembly exported functions are invoked as a regular Python function using an underlying `javascript_function` instance.
194
+
195
+ ```python
196
+ module = wasm_module.from_file("./path/to/module.wasm")
197
+ context.load(module)
198
+
199
+ module.exports.exported_function()
200
+ module.exports.exported_function_with_parameters(convertible, python, args)
201
+ ```
202
+ The following function is currently acting as the module loader on JavaScriptCore's side, it is defined in the context by `wasm_context` upon its allocation.
203
+
204
+ ```javascript
205
+ const _jscore_wasm_modules = {}
206
+ function _jscore_wasm_load(name, wasm_bin, namespace){
207
+ if(namespace === null) { namespace = {}; }
208
+ const wasm_module = new WebAssembly.Module(wasm_bin);
209
+ const wasm_instance = new WebAssembly.Instance(wasm_module, namespace);
210
+ const wasm_module_instance = {"instance": wasm_instance, "namespace": namespace, "module": wasm_module};
211
+ _jscore_wasm_modules[name] = wasm_module_instance; // ensure module remains in scope
212
+ return wasm_module_instance;
213
+ }
214
+ ```
215
+ Calling `wasm_context.load_module` will call this function to create `WebAssembly.Module` and `WebAssebly.Instance` instances in JavaScript with a WebAssembly binary passed as an `Uint8Array` typed array instance and an imports namespace.
216
+
217
+ #### Example: Loading and calling Mozilla's simple.wasm
218
+ An end to end example of loading and using a WebAssembly from Pythonista can be demonstrated by replicating [Mozilla's Loading Wasm Modules in Javascript](https://developer.mozilla.org/en-US/docs/WebAssembly/Guides/Using_the_JavaScript_API#loading_wasm_modules_in_javascript) example.
219
+
220
+ - Firstly, download the [simple.wasm](https://raw.githubusercontent.com/mdn/webassembly-examples/master/js-api-examples/simple.wasm) module from the page.
221
+ - After downloading simple.wasm, the next step is to copy this into Pythonista. To do this, navigate to the simple.wasm file in your Files app, then select the file and open the sharing sheet, then tap "Run Pythonista Script" and then choose the "Import File" option.
222
+ - **Note: This is the only safe way to import .wasm files into Pythonista. The import function from in the Pythonista app itself does not support .wasm files and must not be used to import binary!**
223
+ - Create a folder for your project and copy simple.wasm inside.
224
+ - In your folder with the simple.wasm module create the following script:
225
+
226
+ ```python
227
+
228
+ from jscore_runtime import *
229
+ with (jscore.runtime(wasm_runtime) as runtime, runtime.context() as context):
230
+ # load module file
231
+ module = wasm_module.from_file('./simple.wasm')
232
+ # define imports
233
+ module.imports.my_namespace.imported_func = lambda v: print(v)
234
+ # load module into context
235
+ context.load_module(module)
236
+ # once loaded, a modules exports become available and may be invoked
237
+ module.exports.exported_func() # prints 42
238
+
239
+ # output: 42
240
+ ```
241
+ Modules loading has been made to closely align with javascript with a couple of notable differences, firstly Python functions/callables may be used as imports as well as javascript functions. A fixed imports table is defined per `wasm_module` and `wasm_context`, imports must therefore be specified via the `wasm_module.imports` module specific imports or `wasm_context.imports` context-wide imports properties. A modules imports always override context-wide imports.
242
+
243
+ ## Known issues
244
+ - Loading javascript files from remote sources / cdns etc is not implemented (yet).
245
+ - Modules and scripts loading may not work correctly for some javascript libraries and they may need manual adjustments to work currently.
246
+ - ModulesLoaderDelegate is using a private protcol / api as there is no other way to access the functionality otherwise.
247
+ - JSScript source code strings are C++ objects which are more awkward structures to read with ctypes. A work around of separately loading a copy of the script source is used at the moment, so any module preprocessing performed when loading a JSScript is lost currently.
248
+