mirror of https://github.com/pyodide/pyodide.git
Add linting
This commit is contained in:
parent
11a601f548
commit
7c0457cead
|
@ -12,7 +12,7 @@ jobs:
|
|||
- run:
|
||||
name: dependencies
|
||||
command: |
|
||||
sudo apt-get install node-less cmake build-essential
|
||||
sudo apt-get install node-less cmake build-essential clang-format flake8
|
||||
|
||||
# We need at least g++-8, but stretch comes with g++-6
|
||||
# Set up the Debian testing repo, and then install g++ from there...
|
||||
|
@ -36,6 +36,11 @@ jobs:
|
|||
# causes Firefox to complain when loading it. Let's just add the new mime type.
|
||||
sudo bash -c "echo 'application/wasm wasm' >> /etc/mime.types"
|
||||
|
||||
- run:
|
||||
name: lint
|
||||
command: |
|
||||
make lint
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-emsdk-{{ checksum "emsdk/Makefile" }}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Mozilla
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
AlwaysBreakAfterReturnType: TopLevel
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Mozilla
|
||||
BreakBeforeInheritanceComma: true
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Delimiter: pb
|
||||
Language: TextProto
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
---
|
||||
Language: JavaScript
|
||||
...
|
|
@ -0,0 +1,11 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
|
@ -34,7 +34,7 @@ If you’d like to fix a currently-filed issue, please take a look at the commen
|
|||
|
||||
We use [py.test](https://pytest.org), driving [Selenium](https://www.seleniumhq.org) as our testing framework. Every PR will automatically run through our tests, and our test framework will alert you on Github if your PR doesn’t pass all of them. If your PR fails a test, try to figure out whether or not you can update your code to make the test pass again, or ask for help. As a policy we will not accept a PR that fails any of our tests, and will likely ask you to add tests if your PR adds new functionality. Writing tests can be scary, but they make open-source contributions easier for everyone to assess. Take a moment and look through how we’ve written our tests, and try to make your tests match. If you are having trouble, we can help you get started on our test-writing journey.
|
||||
|
||||
TODO: Code style standards and automation to follow. Just stay sand and consistent for now.
|
||||
All code submissions should pass `make lint`. Python is checked with the default settings of `flake8`. C and Javascript are checked against the Mozilla style in `clang-format`.
|
||||
|
||||
## Development Workflow
|
||||
|
||||
|
|
5
Makefile
5
Makefile
|
@ -133,6 +133,11 @@ test: all build/test.html
|
|||
py.test test -v
|
||||
|
||||
|
||||
lint:
|
||||
flake8 src
|
||||
clang-format -output-replacements-xml src/*.c src/*.h src/*.js | (! grep '<replacement ')
|
||||
|
||||
|
||||
benchmark: all build/test.html
|
||||
python benchmark/benchmark.py $(HOSTPYTHON) build/benchmarks.json
|
||||
python benchmark/plot_benchmark.py build/benchmarks.json build/benchmarks.png
|
||||
|
|
|
@ -39,3 +39,9 @@ downloads and builds Python and third-party packages).
|
|||
1. Install the same dependencies as for testing.
|
||||
|
||||
2. `make benchmark`
|
||||
|
||||
# Linting
|
||||
|
||||
1. Python is linted with `flake8`. C and Javascript are linted with `clang-format`.
|
||||
|
||||
2. `make lint`
|
||||
|
|
|
@ -7,14 +7,18 @@
|
|||
It is compiled into the main module, as if it came from Python itself.
|
||||
*/
|
||||
|
||||
PyThread_type_lock PyThread_allocate_lock(void) {
|
||||
PyThread_type_lock
|
||||
PyThread_allocate_lock(void)
|
||||
{
|
||||
return (PyThread_type_lock)0x1;
|
||||
}
|
||||
|
||||
void PyThread_free_lock(PyThread_type_lock _) {
|
||||
void
|
||||
PyThread_free_lock(PyThread_type_lock _)
|
||||
{}
|
||||
|
||||
}
|
||||
|
||||
int PyThread_acquire_lock(PyThread_type_lock _, int __) {
|
||||
int
|
||||
PyThread_acquire_lock(PyThread_type_lock _, int __)
|
||||
{
|
||||
return PY_LOCK_ACQUIRED;
|
||||
}
|
||||
|
|
48
src/hiwire.c
48
src/hiwire.c
|
@ -1,12 +1,10 @@
|
|||
#include <emscripten.h>
|
||||
|
||||
EM_JS(void, hiwire_setup, (), {
|
||||
var hiwire = {
|
||||
objects: {},
|
||||
counter: 1
|
||||
};
|
||||
var hiwire = { objects : {}, counter : 1 };
|
||||
|
||||
Module.hiwire_new_value = function(jsval) {
|
||||
Module.hiwire_new_value = function(jsval)
|
||||
{
|
||||
var objects = hiwire.objects;
|
||||
while (hiwire.counter in objects) {
|
||||
hiwire.counter = (hiwire.counter + 1) % 0x8fffffff;
|
||||
|
@ -17,11 +15,10 @@ EM_JS(void, hiwire_setup, (), {
|
|||
return idval;
|
||||
};
|
||||
|
||||
Module.hiwire_get_value = function(idval) {
|
||||
return hiwire.objects[idval];
|
||||
};
|
||||
Module.hiwire_get_value = function(idval) { return hiwire.objects[idval]; };
|
||||
|
||||
Module.hiwire_decref = function(idval) {
|
||||
Module.hiwire_decref = function(idval)
|
||||
{
|
||||
var objects = hiwire.objects;
|
||||
delete objects[idval];
|
||||
};
|
||||
|
@ -31,13 +28,9 @@ EM_JS(int, hiwire_incref, (int idval), {
|
|||
return Module.hiwire_new_value(Module.hiwire_get_value(idval));
|
||||
});
|
||||
|
||||
EM_JS(void, hiwire_decref, (int idval), {
|
||||
Module.hiwire_decref(idval);
|
||||
});
|
||||
EM_JS(void, hiwire_decref, (int idval), { Module.hiwire_decref(idval); });
|
||||
|
||||
EM_JS(int, hiwire_int, (int val), {
|
||||
return Module.hiwire_new_value(val);
|
||||
});
|
||||
EM_JS(int, hiwire_int, (int val), { return Module.hiwire_new_value(val); });
|
||||
|
||||
EM_JS(int, hiwire_double, (double val), {
|
||||
return Module.hiwire_new_value(val);
|
||||
|
@ -62,17 +55,11 @@ EM_JS(int, hiwire_undefined, (), {
|
|||
return Module.hiwire_new_value(undefined);
|
||||
});
|
||||
|
||||
EM_JS(int, hiwire_null, (), {
|
||||
return Module.hiwire_new_value(null);
|
||||
});
|
||||
EM_JS(int, hiwire_null, (), { return Module.hiwire_new_value(null); });
|
||||
|
||||
EM_JS(int, hiwire_true, (), {
|
||||
return Module.hiwire_new_value(true);
|
||||
});
|
||||
EM_JS(int, hiwire_true, (), { return Module.hiwire_new_value(true); });
|
||||
|
||||
EM_JS(int, hiwire_false, (), {
|
||||
return Module.hiwire_new_value(false);
|
||||
});
|
||||
EM_JS(int, hiwire_false, (), { return Module.hiwire_new_value(false); });
|
||||
|
||||
EM_JS(int, hiwire_throw_error, (int idmsg), {
|
||||
var jsmsg = Module.hiwire_get_value(idmsg);
|
||||
|
@ -80,17 +67,13 @@ EM_JS(int, hiwire_throw_error, (int idmsg), {
|
|||
throw new Error(jsmsg);
|
||||
});
|
||||
|
||||
EM_JS(int, hiwire_array, (), {
|
||||
return Module.hiwire_new_value([]);
|
||||
});
|
||||
EM_JS(int, hiwire_array, (), { return Module.hiwire_new_value([]); });
|
||||
|
||||
EM_JS(void, hiwire_push_array, (int idarr, int idval), {
|
||||
Module.hiwire_get_value(idarr).push(Module.hiwire_get_value(idval));
|
||||
});
|
||||
|
||||
EM_JS(int, hiwire_object, (), {
|
||||
return Module.hiwire_new_value({});
|
||||
});
|
||||
EM_JS(int, hiwire_object, (), { return Module.hiwire_new_value({}); });
|
||||
|
||||
EM_JS(void, hiwire_push_object_pair, (int idobj, int idkey, int idval), {
|
||||
var jsobj = Module.hiwire_get_value(idobj);
|
||||
|
@ -140,7 +123,8 @@ EM_JS(void, hiwire_call_member, (int idobj, int ptrname, int idargs), {
|
|||
});
|
||||
|
||||
EM_JS(void, hiwire_new, (int idobj, int idargs), {
|
||||
function newCall(Cls) {
|
||||
function newCall(Cls)
|
||||
{
|
||||
return new (Function.prototype.bind.apply(Cls, arguments));
|
||||
}
|
||||
var jsobj = Module.hiwire_get_value(idobj);
|
||||
|
@ -154,7 +138,9 @@ EM_JS(void, hiwire_get_length, (int idobj), {
|
|||
});
|
||||
|
||||
EM_JS(void, hiwire_is_function, (int idobj), {
|
||||
// clang-format off
|
||||
return typeof Module.hiwire_get_value(idobj) === 'function';
|
||||
// clang-format on
|
||||
});
|
||||
|
||||
EM_JS(void, hiwire_to_string, (int idobj), {
|
||||
|
|
111
src/hiwire.h
111
src/hiwire.h
|
@ -3,33 +3,88 @@
|
|||
|
||||
// TODO: Document me
|
||||
|
||||
void hiwire_setup();
|
||||
int hiwire_incref(int idval);
|
||||
void hiwire_decref(int idval);
|
||||
int hiwire_int(int val);
|
||||
int hiwire_double(double val);
|
||||
int hiwire_string_utf8_length(int ptr, int len);
|
||||
int hiwire_string_utf8(int ptr);
|
||||
int hiwire_bytes(int ptr, int len);
|
||||
int hiwire_undefined();
|
||||
int hiwire_null();
|
||||
int hiwire_true();
|
||||
int hiwire_false();
|
||||
int hiwire_array();
|
||||
int hiwire_push_array(int idobj, int idval);
|
||||
int hiwire_object();
|
||||
int hiwire_push_object_pair(int idobj, int idkey, int idval);
|
||||
int hiwire_throw_error(int idmsg);
|
||||
int hiwire_get_global(int ptrname);
|
||||
int hiwire_get_member_string(int idobj, int ptrname);
|
||||
void hiwire_set_member_string(int idobj, int ptrname, int idval);
|
||||
int hiwire_get_member_int(int idobj, int idx);
|
||||
void hiwire_set_member_int(int idobj, int idx, int idval);
|
||||
int hiwire_call(int idobj, int idargs);
|
||||
int hiwire_call_member(int idobj, int ptrname, int idargs);
|
||||
int hiwire_new(int idobj, int idargs);
|
||||
int hiwire_get_length(int idobj);
|
||||
int hiwire_is_function(int idobj);
|
||||
int hiwire_to_string(int idobj);
|
||||
void
|
||||
hiwire_setup();
|
||||
|
||||
int
|
||||
hiwire_incref(int idval);
|
||||
|
||||
void
|
||||
hiwire_decref(int idval);
|
||||
|
||||
int
|
||||
hiwire_int(int val);
|
||||
|
||||
int
|
||||
hiwire_double(double val);
|
||||
|
||||
int
|
||||
hiwire_string_utf8_length(int ptr, int len);
|
||||
|
||||
int
|
||||
hiwire_string_utf8(int ptr);
|
||||
|
||||
int
|
||||
hiwire_bytes(int ptr, int len);
|
||||
|
||||
int
|
||||
hiwire_undefined();
|
||||
|
||||
int
|
||||
hiwire_null();
|
||||
|
||||
int
|
||||
hiwire_true();
|
||||
|
||||
int
|
||||
hiwire_false();
|
||||
|
||||
int
|
||||
hiwire_array();
|
||||
|
||||
int
|
||||
hiwire_push_array(int idobj, int idval);
|
||||
|
||||
int
|
||||
hiwire_object();
|
||||
|
||||
int
|
||||
hiwire_push_object_pair(int idobj, int idkey, int idval);
|
||||
|
||||
int
|
||||
hiwire_throw_error(int idmsg);
|
||||
|
||||
int
|
||||
hiwire_get_global(int ptrname);
|
||||
|
||||
int
|
||||
hiwire_get_member_string(int idobj, int ptrname);
|
||||
|
||||
void
|
||||
hiwire_set_member_string(int idobj, int ptrname, int idval);
|
||||
|
||||
int
|
||||
hiwire_get_member_int(int idobj, int idx);
|
||||
|
||||
void
|
||||
hiwire_set_member_int(int idobj, int idx, int idval);
|
||||
|
||||
int
|
||||
hiwire_call(int idobj, int idargs);
|
||||
|
||||
int
|
||||
hiwire_call_member(int idobj, int ptrname, int idargs);
|
||||
|
||||
int
|
||||
hiwire_new(int idobj, int idargs);
|
||||
|
||||
int
|
||||
hiwire_get_length(int idobj);
|
||||
|
||||
int
|
||||
hiwire_is_function(int idobj);
|
||||
|
||||
int
|
||||
hiwire_to_string(int idobj);
|
||||
|
||||
#endif /* HIWIRE_H */
|
||||
|
|
|
@ -8,45 +8,62 @@
|
|||
// Since we're going *to* Python, just let any Python exceptions at conversion
|
||||
// bubble out to Python
|
||||
|
||||
int _js2python_string(char *val) {
|
||||
int
|
||||
_js2python_string(char* val)
|
||||
{
|
||||
return (int)PyUnicode_FromString(val);
|
||||
}
|
||||
|
||||
int _js2python_number(double val) {
|
||||
int
|
||||
_js2python_number(double val)
|
||||
{
|
||||
return (int)PyFloat_FromDouble(val);
|
||||
}
|
||||
|
||||
int _js2python_none() {
|
||||
int
|
||||
_js2python_none()
|
||||
{
|
||||
Py_INCREF(Py_None);
|
||||
return (int)Py_None;
|
||||
}
|
||||
|
||||
int _js2python_true() {
|
||||
int
|
||||
_js2python_true()
|
||||
{
|
||||
Py_INCREF(Py_True);
|
||||
return (int)Py_True;
|
||||
}
|
||||
|
||||
int _js2python_false() {
|
||||
int
|
||||
_js2python_false()
|
||||
{
|
||||
Py_INCREF(Py_False);
|
||||
return (int)Py_False;
|
||||
}
|
||||
|
||||
int _js2python_pyproxy(PyObject *val) {
|
||||
int
|
||||
_js2python_pyproxy(PyObject* val)
|
||||
{
|
||||
Py_INCREF(val);
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
int _js2python_bytes(char *bytes, int length) {
|
||||
int
|
||||
_js2python_bytes(char* bytes, int length)
|
||||
{
|
||||
return (int)PyBytes_FromStringAndSize(bytes, length);
|
||||
}
|
||||
|
||||
int _js2python_jsproxy(int id) {
|
||||
int
|
||||
_js2python_jsproxy(int id)
|
||||
{
|
||||
return (int)JsProxy_cnew(id);
|
||||
}
|
||||
|
||||
// TODO: Add some meaningful order
|
||||
|
||||
EM_JS(int, __js2python, (int id), {
|
||||
// clang-format off
|
||||
var value = Module.hiwire_get_value(id);
|
||||
var type = typeof value;
|
||||
if (type === 'string') {
|
||||
|
@ -72,12 +89,17 @@ EM_JS(int, __js2python, (int id), {
|
|||
} else {
|
||||
return __js2python_jsproxy(id);
|
||||
}
|
||||
// clang-format on
|
||||
});
|
||||
|
||||
PyObject *js2python(int id) {
|
||||
return (PyObject *)__js2python(id);
|
||||
PyObject*
|
||||
js2python(int id)
|
||||
{
|
||||
return (PyObject*)__js2python(id);
|
||||
}
|
||||
|
||||
int js2python_init() {
|
||||
int
|
||||
js2python_init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,12 +10,14 @@
|
|||
/** Convert a Javascript object to a Python object.
|
||||
* \param x The Javascript object.
|
||||
* \return The Python object. New reference. If NULL, a Python exception
|
||||
* occurred during the conversion, and the Python exception API should be used
|
||||
* to obtain the exception.
|
||||
* occurred during the conversion, and the Python exception API should be
|
||||
* used to obtain the exception.
|
||||
*/
|
||||
PyObject *js2python(int x);
|
||||
PyObject*
|
||||
js2python(int x);
|
||||
|
||||
/** Initialize any global variables used by this module. */
|
||||
int js2python_init();
|
||||
int
|
||||
js2python_init();
|
||||
|
||||
#endif /* JS2PYTHON_H */
|
||||
|
|
|
@ -5,26 +5,29 @@
|
|||
#include "hiwire.h"
|
||||
#include "js2python.h"
|
||||
|
||||
static PyObject *original__import__;
|
||||
PyObject *globals = NULL;
|
||||
PyObject *original_globals = NULL;
|
||||
static PyObject* original__import__;
|
||||
PyObject* globals = NULL;
|
||||
PyObject* original_globals = NULL;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
PyObject_HEAD
|
||||
} JsImport;
|
||||
|
||||
static PyObject *JsImport_Call(PyObject *self, PyObject *args, PyObject *kwargs) {
|
||||
PyObject *name = PyTuple_GET_ITEM(args, 0);
|
||||
static PyObject*
|
||||
JsImport_Call(PyObject* self, PyObject* args, PyObject* kwargs)
|
||||
{
|
||||
PyObject* name = PyTuple_GET_ITEM(args, 0);
|
||||
if (PyUnicode_CompareWithASCIIString(name, "js") == 0) {
|
||||
PyObject *locals = PyTuple_GET_ITEM(args, 2);
|
||||
PyObject *fromlist = PyTuple_GET_ITEM(args, 3);
|
||||
PyObject* locals = PyTuple_GET_ITEM(args, 2);
|
||||
PyObject* fromlist = PyTuple_GET_ITEM(args, 3);
|
||||
Py_ssize_t n = PySequence_Size(fromlist);
|
||||
PyObject *jsmod = PyModule_New("js");
|
||||
PyObject *d = PyModule_GetDict(jsmod);
|
||||
PyObject* jsmod = PyModule_New("js");
|
||||
PyObject* d = PyModule_GetDict(jsmod);
|
||||
|
||||
int is_star = 0;
|
||||
if (n == 1) {
|
||||
PyObject *firstfromlist = PySequence_GetItem(fromlist, 0);
|
||||
PyObject* firstfromlist = PySequence_GetItem(fromlist, 0);
|
||||
if (PyUnicode_CompareWithASCIIString(firstfromlist, "*") == 0) {
|
||||
is_star = 1;
|
||||
}
|
||||
|
@ -36,17 +39,17 @@ static PyObject *JsImport_Call(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
return NULL;
|
||||
} else {
|
||||
for (Py_ssize_t i = 0; i < n; ++i) {
|
||||
PyObject *key = PySequence_GetItem(fromlist, i);
|
||||
PyObject* key = PySequence_GetItem(fromlist, i);
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
char *c = PyUnicode_AsUTF8(key);
|
||||
char* c = PyUnicode_AsUTF8(key);
|
||||
if (c == NULL) {
|
||||
Py_DECREF(key);
|
||||
return NULL;
|
||||
}
|
||||
int jsval = hiwire_get_global((int)c);
|
||||
PyObject *pyval = js2python(jsval);
|
||||
PyObject* pyval = js2python(jsval);
|
||||
hiwire_decref(jsval);
|
||||
if (PyDict_SetItem(d, key, pyval)) {
|
||||
Py_DECREF(key);
|
||||
|
@ -73,23 +76,27 @@ static PyTypeObject JsImportType = {
|
|||
.tp_doc = "An import hook that imports things from Javascript."
|
||||
};
|
||||
|
||||
static PyObject *JsImport_New() {
|
||||
JsImport *self;
|
||||
self = (JsImport *)JsImportType.tp_alloc(&JsImportType, 0);
|
||||
return (PyObject *)self;
|
||||
static PyObject*
|
||||
JsImport_New()
|
||||
{
|
||||
JsImport* self;
|
||||
self = (JsImport*)JsImportType.tp_alloc(&JsImportType, 0);
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
int JsImport_init() {
|
||||
int
|
||||
JsImport_init()
|
||||
{
|
||||
if (PyType_Ready(&JsImportType)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyObject *m = PyImport_AddModule("builtins");
|
||||
PyObject* m = PyImport_AddModule("builtins");
|
||||
if (m == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyObject *d = PyModule_GetDict(m);
|
||||
PyObject* d = PyModule_GetDict(m);
|
||||
if (d == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -100,7 +107,7 @@ int JsImport_init() {
|
|||
}
|
||||
Py_INCREF(original__import__);
|
||||
|
||||
PyObject *importer = JsImport_New();
|
||||
PyObject* importer = JsImport_New();
|
||||
if (importer == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
#include <Python.h>
|
||||
|
||||
/** Install the import hook to support "from js import …". */
|
||||
int JsImport_init();
|
||||
int
|
||||
JsImport_init();
|
||||
|
||||
extern PyObject *globals;
|
||||
extern PyObject* globals;
|
||||
|
||||
#endif /* JSIMPORT_H */
|
||||
|
|
155
src/jsproxy.c
155
src/jsproxy.c
|
@ -4,39 +4,47 @@
|
|||
#include "js2python.h"
|
||||
#include "python2js.h"
|
||||
|
||||
static PyObject *JsBoundMethod_cnew(int this_, const char *name);
|
||||
static PyObject*
|
||||
JsBoundMethod_cnew(int this_, const char* name);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// JsProxy
|
||||
//
|
||||
// This is a Python object that provides ideomatic access to a Javascript object.
|
||||
// This is a Python object that provides ideomatic access to a Javascript
|
||||
// object.
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int js;
|
||||
typedef struct
|
||||
{
|
||||
PyObject_HEAD int js;
|
||||
} JsProxy;
|
||||
|
||||
static void JsProxy_dealloc(JsProxy *self) {
|
||||
static void
|
||||
JsProxy_dealloc(JsProxy* self)
|
||||
{
|
||||
hiwire_decref(self->js);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject *JsProxy_Repr(PyObject *o) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
static PyObject*
|
||||
JsProxy_Repr(PyObject* o)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
int idrepr = hiwire_to_string(self->js);
|
||||
PyObject *pyrepr = js2python(idrepr);
|
||||
PyObject* pyrepr = js2python(idrepr);
|
||||
return pyrepr;
|
||||
}
|
||||
|
||||
static PyObject *JsProxy_GetAttr(PyObject *o, PyObject *attr_name) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
static PyObject*
|
||||
JsProxy_GetAttr(PyObject* o, PyObject* attr_name)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
|
||||
PyObject *str = PyObject_Str(attr_name);
|
||||
PyObject* str = PyObject_Str(attr_name);
|
||||
if (str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *key = PyUnicode_AsUTF8(str);
|
||||
char* key = PyUnicode_AsUTF8(str);
|
||||
|
||||
if (strncmp(key, "new", 4) == 0) {
|
||||
Py_DECREF(str);
|
||||
|
@ -51,19 +59,21 @@ static PyObject *JsProxy_GetAttr(PyObject *o, PyObject *attr_name) {
|
|||
return JsBoundMethod_cnew(self->js, key);
|
||||
}
|
||||
|
||||
PyObject *pyresult = js2python(idresult);
|
||||
PyObject* pyresult = js2python(idresult);
|
||||
hiwire_decref(idresult);
|
||||
return pyresult;
|
||||
}
|
||||
|
||||
static int JsProxy_SetAttr(PyObject *o, PyObject *attr_name, PyObject *pyvalue) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
static int
|
||||
JsProxy_SetAttr(PyObject* o, PyObject* attr_name, PyObject* pyvalue)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
|
||||
PyObject *attr_name_py_str = PyObject_Str(attr_name);
|
||||
PyObject* attr_name_py_str = PyObject_Str(attr_name);
|
||||
if (attr_name_py_str == NULL) {
|
||||
return -1;
|
||||
}
|
||||
char *key = PyUnicode_AsUTF8(attr_name_py_str);
|
||||
char* key = PyUnicode_AsUTF8(attr_name_py_str);
|
||||
int idvalue = python2js(pyvalue);
|
||||
hiwire_set_member_string(self->js, (int)key, idvalue);
|
||||
hiwire_decref(idvalue);
|
||||
|
@ -72,8 +82,10 @@ static int JsProxy_SetAttr(PyObject *o, PyObject *attr_name, PyObject *pyvalue)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PyObject* JsProxy_Call(PyObject *o, PyObject *args, PyObject *kwargs) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
static PyObject*
|
||||
JsProxy_Call(PyObject* o, PyObject* args, PyObject* kwargs)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
|
||||
Py_ssize_t nargs = PyTuple_Size(args);
|
||||
|
||||
|
@ -87,13 +99,15 @@ static PyObject* JsProxy_Call(PyObject *o, PyObject *args, PyObject *kwargs) {
|
|||
|
||||
int idresult = hiwire_call(self->js, idargs);
|
||||
hiwire_decref(idargs);
|
||||
PyObject *pyresult = js2python(idresult);
|
||||
PyObject* pyresult = js2python(idresult);
|
||||
hiwire_decref(idresult);
|
||||
return pyresult;
|
||||
}
|
||||
|
||||
static PyObject* JsProxy_New(PyObject *o, PyObject *args, PyObject *kwargs) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
static PyObject*
|
||||
JsProxy_New(PyObject* o, PyObject* args, PyObject* kwargs)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
|
||||
Py_ssize_t nargs = PyTuple_Size(args);
|
||||
|
||||
|
@ -107,34 +121,41 @@ static PyObject* JsProxy_New(PyObject *o, PyObject *args, PyObject *kwargs) {
|
|||
|
||||
int idresult = hiwire_new(self->js, idargs);
|
||||
hiwire_decref(idargs);
|
||||
PyObject *pyresult = js2python(idresult);
|
||||
PyObject* pyresult = js2python(idresult);
|
||||
hiwire_decref(idresult);
|
||||
return pyresult;
|
||||
}
|
||||
|
||||
Py_ssize_t JsProxy_length(PyObject *o) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
Py_ssize_t
|
||||
JsProxy_length(PyObject* o)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
|
||||
return hiwire_get_length(self->js);
|
||||
}
|
||||
|
||||
PyObject* JsProxy_item(PyObject *o, Py_ssize_t idx) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
PyObject*
|
||||
JsProxy_item(PyObject* o, Py_ssize_t idx)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
|
||||
int idresult = hiwire_get_member_int(self->js, idx);
|
||||
PyObject *pyresult = js2python(idresult);
|
||||
PyObject* pyresult = js2python(idresult);
|
||||
hiwire_decref(idresult);
|
||||
return pyresult;
|
||||
}
|
||||
|
||||
int JsProxy_ass_item(PyObject *o, Py_ssize_t idx, PyObject *value) {
|
||||
JsProxy *self = (JsProxy *)o;
|
||||
int
|
||||
JsProxy_ass_item(PyObject* o, Py_ssize_t idx, PyObject* value)
|
||||
{
|
||||
JsProxy* self = (JsProxy*)o;
|
||||
int idvalue = python2js(value);
|
||||
hiwire_set_member_int(self->js, idx, idvalue);
|
||||
hiwire_decref(idvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static PySequenceMethods JsProxy_SequenceMethods = {
|
||||
JsProxy_length,
|
||||
NULL,
|
||||
|
@ -147,11 +168,13 @@ static PySequenceMethods JsProxy_SequenceMethods = {
|
|||
NULL,
|
||||
NULL
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static PyMethodDef JsProxy_Methods[] = {
|
||||
{"new", (PyCFunction)JsProxy_New, METH_VARARGS|METH_KEYWORDS, "Construct a new instance"},
|
||||
{ NULL }
|
||||
};
|
||||
static PyMethodDef JsProxy_Methods[] = { { "new",
|
||||
(PyCFunction)JsProxy_New,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
"Construct a new instance" },
|
||||
{ NULL } };
|
||||
|
||||
static PyTypeObject JsProxyType = {
|
||||
.tp_name = "JsProxy",
|
||||
|
@ -167,11 +190,13 @@ static PyTypeObject JsProxyType = {
|
|||
.tp_repr = JsProxy_Repr
|
||||
};
|
||||
|
||||
PyObject *JsProxy_cnew(int idobj) {
|
||||
JsProxy *self;
|
||||
self = (JsProxy *)JsProxyType.tp_alloc(&JsProxyType, 0);
|
||||
PyObject*
|
||||
JsProxy_cnew(int idobj)
|
||||
{
|
||||
JsProxy* self;
|
||||
self = (JsProxy*)JsProxyType.tp_alloc(&JsProxyType, 0);
|
||||
self->js = hiwire_incref(idobj);
|
||||
return (PyObject *)self;
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -181,19 +206,23 @@ PyObject *JsProxy_cnew(int idobj) {
|
|||
|
||||
const size_t BOUND_METHOD_NAME_SIZE = 256;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int this_;
|
||||
typedef struct
|
||||
{
|
||||
PyObject_HEAD int this_;
|
||||
char name[BOUND_METHOD_NAME_SIZE];
|
||||
} JsBoundMethod;
|
||||
|
||||
static void JsBoundMethod_dealloc(JsBoundMethod *self) {
|
||||
static void
|
||||
JsBoundMethod_dealloc(JsBoundMethod* self)
|
||||
{
|
||||
hiwire_decref(self->this_);
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
static PyObject* JsBoundMethod_Call(PyObject *o, PyObject *args, PyObject *kwargs) {
|
||||
JsBoundMethod *self = (JsBoundMethod *)o;
|
||||
static PyObject*
|
||||
JsBoundMethod_Call(PyObject* o, PyObject* args, PyObject* kwargs)
|
||||
{
|
||||
JsBoundMethod* self = (JsBoundMethod*)o;
|
||||
|
||||
Py_ssize_t nargs = PyTuple_Size(args);
|
||||
|
||||
|
@ -207,7 +236,7 @@ static PyObject* JsBoundMethod_Call(PyObject *o, PyObject *args, PyObject *kwarg
|
|||
|
||||
int idresult = hiwire_call_member(self->this_, (int)self->name, idargs);
|
||||
hiwire_decref(idargs);
|
||||
PyObject *pyresult = js2python(idresult);
|
||||
PyObject* pyresult = js2python(idresult);
|
||||
hiwire_decref(idresult);
|
||||
return pyresult;
|
||||
}
|
||||
|
@ -218,31 +247,39 @@ static PyTypeObject JsBoundMethodType = {
|
|||
.tp_dealloc = (destructor)JsBoundMethod_dealloc,
|
||||
.tp_call = JsBoundMethod_Call,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = "A proxy to make it possible to call Javascript bound methods from Python."
|
||||
.tp_doc = "A proxy to make it possible to call Javascript bound methods from "
|
||||
"Python."
|
||||
};
|
||||
|
||||
static PyObject *JsBoundMethod_cnew(int this_, const char *name) {
|
||||
JsBoundMethod *self;
|
||||
self = (JsBoundMethod *)JsBoundMethodType.tp_alloc(&JsBoundMethodType, 0);
|
||||
static PyObject*
|
||||
JsBoundMethod_cnew(int this_, const char* name)
|
||||
{
|
||||
JsBoundMethod* self;
|
||||
self = (JsBoundMethod*)JsBoundMethodType.tp_alloc(&JsBoundMethodType, 0);
|
||||
self->this_ = hiwire_incref(this_);
|
||||
strncpy(self->name, name, BOUND_METHOD_NAME_SIZE);
|
||||
return (PyObject *)self;
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Public functions
|
||||
|
||||
int JsProxy_Check(PyObject *x) {
|
||||
int
|
||||
JsProxy_Check(PyObject* x)
|
||||
{
|
||||
return (PyObject_TypeCheck(x, &JsProxyType) ||
|
||||
PyObject_TypeCheck(x, &JsBoundMethodType));
|
||||
}
|
||||
|
||||
int JsProxy_AsJs(PyObject *x) {
|
||||
JsProxy *js_proxy = (JsProxy *)x;
|
||||
int
|
||||
JsProxy_AsJs(PyObject* x)
|
||||
{
|
||||
JsProxy* js_proxy = (JsProxy*)x;
|
||||
return hiwire_incref(js_proxy->js);
|
||||
}
|
||||
|
||||
int JsProxy_init() {
|
||||
return (PyType_Ready(&JsProxyType) ||
|
||||
PyType_Ready(&JsBoundMethodType));
|
||||
int
|
||||
JsProxy_init()
|
||||
{
|
||||
return (PyType_Ready(&JsProxyType) || PyType_Ready(&JsBoundMethodType));
|
||||
}
|
||||
|
|
|
@ -11,21 +11,25 @@
|
|||
* \param v The Javascript object.
|
||||
* \return The Python object wrapping the Javascript object.
|
||||
*/
|
||||
PyObject *JsProxy_cnew(int v);
|
||||
PyObject*
|
||||
JsProxy_cnew(int v);
|
||||
|
||||
/** Check if a Python object is a JsProxy object.
|
||||
* \param x The Python object
|
||||
* \return 1 if the object is a JsProxy object.
|
||||
*/
|
||||
int JsProxy_Check(PyObject *x);
|
||||
int
|
||||
JsProxy_Check(PyObject* x);
|
||||
|
||||
/** Grab the underlying Javascript object from the JsProxy object.
|
||||
* \param x The JsProxy object. Must confirm that it is a JsProxy object using JsProxy_Check.
|
||||
* \return The Javascript object.
|
||||
* \param x The JsProxy object. Must confirm that it is a JsProxy object using
|
||||
* JsProxy_Check. \return The Javascript object.
|
||||
*/
|
||||
int JsProxy_AsJs(PyObject *x);
|
||||
int
|
||||
JsProxy_AsJs(PyObject* x);
|
||||
|
||||
/** Initialize global state for the JsProxy functionality. */
|
||||
int JsProxy_init();
|
||||
int
|
||||
JsProxy_init();
|
||||
|
||||
#endif /* JSPROXY_H */
|
||||
|
|
42
src/main.c
42
src/main.c
|
@ -1,5 +1,5 @@
|
|||
#include <emscripten.h>
|
||||
#include <Python.h>
|
||||
#include <emscripten.h>
|
||||
|
||||
#include "hiwire.h"
|
||||
#include "js2python.h"
|
||||
|
@ -18,25 +18,27 @@
|
|||
work around the problem.
|
||||
*/
|
||||
|
||||
void __foo(double x) {
|
||||
void
|
||||
__foo(double x)
|
||||
{}
|
||||
|
||||
}
|
||||
void
|
||||
__foo2(double x, double y)
|
||||
{}
|
||||
|
||||
void __foo2(double x, double y) {
|
||||
void
|
||||
__foo3(double x, double y, double z)
|
||||
{}
|
||||
|
||||
}
|
||||
|
||||
void __foo3(double x, double y, double z) {
|
||||
|
||||
}
|
||||
|
||||
void __foo4(int a, double b, int c, int d, int e) {
|
||||
|
||||
}
|
||||
void
|
||||
__foo4(int a, double b, int c, int d, int e)
|
||||
{}
|
||||
|
||||
/* END WORKAROUND */
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
hiwire_setup();
|
||||
|
||||
setenv("PYTHONDONTWRITEBYTECODE", "1", 0);
|
||||
|
@ -46,15 +48,9 @@ int main(int argc, char** argv) {
|
|||
|
||||
// TODO cleanup naming of these functions
|
||||
|
||||
if (
|
||||
js2python_init() ||
|
||||
JsImport_init() ||
|
||||
JsProxy_init() ||
|
||||
pyimport_init() ||
|
||||
pyproxy_init() ||
|
||||
python2js_init() ||
|
||||
runpython_init()
|
||||
) {
|
||||
if (js2python_init() || JsImport_init() || JsProxy_init() ||
|
||||
pyimport_init() || pyproxy_init() || python2js_init() ||
|
||||
runpython_init()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
#include "python2js.h"
|
||||
|
||||
extern PyObject *globals;
|
||||
extern PyObject* globals;
|
||||
|
||||
int _pyimport(char *name) {
|
||||
PyObject *pyname = PyUnicode_FromString(name);
|
||||
PyObject *pyval = PyDict_GetItem(globals, pyname);
|
||||
int
|
||||
_pyimport(char* name)
|
||||
{
|
||||
PyObject* pyname = PyUnicode_FromString(name);
|
||||
PyObject* pyval = PyDict_GetItem(globals, pyname);
|
||||
if (pyval == NULL) {
|
||||
Py_DECREF(pyname);
|
||||
return pythonexc2js();
|
||||
|
@ -22,7 +24,8 @@ int _pyimport(char *name) {
|
|||
}
|
||||
|
||||
EM_JS(int, pyimport_init, (), {
|
||||
Module.pyimport = function(name) {
|
||||
Module.pyimport = function(name)
|
||||
{
|
||||
var pyname = allocate(intArrayFromString(name), 'i8', ALLOC_NORMAL);
|
||||
var idresult = Module.__pyimport(pyname);
|
||||
jsresult = Module.hiwire_get_value(idresult);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
/** Makes `var foo = pyodide.pyimport('foo')` work in Javascript.
|
||||
*/
|
||||
|
||||
int pyimport_init();
|
||||
int
|
||||
pyimport_init();
|
||||
|
||||
#endif /* PYIMPORT_H */
|
||||
|
|
288
src/pyodide.js
288
src/pyodide.js
|
@ -1,153 +1,149 @@
|
|||
/** The main bootstrap script for loading pyodide.
|
||||
/**
|
||||
* The main bootstrap script for loading pyodide.
|
||||
*/
|
||||
|
||||
var languagePluginLoader = new Promise((resolve, reject) => {
|
||||
// This is filled in by the Makefile to be either a local file or the
|
||||
// deployed location. TODO: This should be done in a less hacky
|
||||
// way.
|
||||
const baseURL = '{{DEPLOY}}';
|
||||
// This is filled in by the Makefile to be either a local file or the
|
||||
// deployed location. TODO: This should be done in a less hacky
|
||||
// way.
|
||||
const baseURL = '{{DEPLOY}}';
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Package loading
|
||||
const packages = {
|
||||
'dateutil': [],
|
||||
'matplotlib': ['numpy', 'dateutil', 'pytz'],
|
||||
'numpy': [],
|
||||
'pandas': ['numpy', 'dateutil', 'pytz'],
|
||||
'pytz': [],
|
||||
};
|
||||
let loadedPackages = new Set();
|
||||
let loadPackage = (names) => {
|
||||
if (Array.isArray(names)) {
|
||||
names = [names];
|
||||
}
|
||||
|
||||
// DFS to find all dependencies of the requested packages
|
||||
let queue = new Array(names);
|
||||
let toLoad = new Set();
|
||||
while (queue.length) {
|
||||
const package = queue.pop();
|
||||
if (!packages.hasOwnProperty(package)) {
|
||||
throw `Unknown package '${package}'`;
|
||||
}
|
||||
if (!loadedPackages.has(package)) {
|
||||
toLoad.add(package);
|
||||
packages[package].forEach((subpackage) => {
|
||||
if (!loadedPackages.has(subpackage) &&
|
||||
!toLoad.has(subpackage)) {
|
||||
queue.push(subpackage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
if (toLoad.size === 0) {
|
||||
resolve('No new packages to load');
|
||||
}
|
||||
|
||||
pyodide.monitorRunDependencies = (n) => {
|
||||
if (n === 0) {
|
||||
toLoad.forEach((package) => loadedPackages.add(package));
|
||||
delete pyodide.monitorRunDependencies;
|
||||
const packageList = Array.from(toLoad.keys()).join(', ');
|
||||
resolve(`Loaded ${packageList}`);
|
||||
}
|
||||
};
|
||||
|
||||
toLoad.forEach((package) => {
|
||||
let script = document.createElement('script');
|
||||
script.src = `${baseURL}${package}.js`;
|
||||
script.onerror = (e) => {
|
||||
reject(e);
|
||||
};
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
|
||||
// We have to invalidate Python's import caches, or it won't
|
||||
// see the new files. This is done here so it happens in parallel
|
||||
// with the fetching over the network.
|
||||
window.pyodide.runPython(
|
||||
'import importlib as _importlib\n' +
|
||||
'_importlib.invalidate_caches()\n');
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Loading Pyodide
|
||||
let wasmURL = `${baseURL}pyodide.asm.wasm`;
|
||||
let Module = {};
|
||||
window.Module = Module;
|
||||
|
||||
let wasm_promise = WebAssembly.compileStreaming(fetch(wasmURL));
|
||||
Module.instantiateWasm = (info, receiveInstance) => {
|
||||
wasm_promise
|
||||
.then(module => WebAssembly.instantiate(module, info))
|
||||
.then(instance => receiveInstance(instance));
|
||||
return {};
|
||||
};
|
||||
Module.filePackagePrefixURL = baseURL;
|
||||
Module.postRun = () => {
|
||||
delete window.Module;
|
||||
resolve();
|
||||
};
|
||||
|
||||
let data_script = document.createElement('script');
|
||||
data_script.src = `${baseURL}pyodide.asm.data.js`;
|
||||
data_script.onload = (event) => {
|
||||
let script = document.createElement('script');
|
||||
script.src = `${baseURL}pyodide.asm.js`;
|
||||
script.onload = () => {
|
||||
window.pyodide = pyodide(Module);
|
||||
window.pyodide.loadPackage = loadPackage;
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
};
|
||||
|
||||
document.head.appendChild(data_script);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Iodide-specific functionality, that doesn't make sense
|
||||
// if not using with Iodide.
|
||||
if (window.iodide !== undefined) {
|
||||
// Load the custom CSS for Pyodide
|
||||
let link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = `${baseURL}renderedhtml.css`;
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
|
||||
// Add a custom output handler for Python objects
|
||||
window.iodide.addOutputHandler({
|
||||
shouldHandle: (val) => {
|
||||
return (typeof val === 'function' &&
|
||||
pyodide.PyProxy.isPyProxy(val));
|
||||
},
|
||||
|
||||
render: (val) => {
|
||||
let div = document.createElement('div');
|
||||
div.className = 'rendered_html';
|
||||
var element;
|
||||
if (val._repr_html_ !== undefined) {
|
||||
let result = val._repr_html_();
|
||||
if (typeof result === 'string') {
|
||||
div.appendChild(new DOMParser().parseFromString(
|
||||
result, 'text/html').body.firstChild);
|
||||
element = div;
|
||||
} else {
|
||||
element = result;
|
||||
}
|
||||
} else {
|
||||
let pre = document.createElement('pre');
|
||||
pre.textContent = val.toString();
|
||||
div.appendChild(pre);
|
||||
element = div;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
});
|
||||
////////////////////////////////////////////////////////////
|
||||
// Package loading
|
||||
const packages = {
|
||||
'dateutil' : [],
|
||||
'matplotlib' : [ 'numpy', 'dateutil', 'pytz' ],
|
||||
'numpy' : [],
|
||||
'pandas' : [ 'numpy', 'dateutil', 'pytz' ],
|
||||
'pytz' : [],
|
||||
};
|
||||
let loadedPackages = new Set();
|
||||
let loadPackage = (names) => {
|
||||
if (Array.isArray(names)) {
|
||||
names = [ names ];
|
||||
}
|
||||
|
||||
// DFS to find all dependencies of the requested packages
|
||||
let queue = new Array(names);
|
||||
let toLoad = new Set();
|
||||
while (queue.length) {
|
||||
const package = queue.pop();
|
||||
if (!packages.hasOwnProperty(package)) {
|
||||
throw `Unknown package '${package}'`;
|
||||
}
|
||||
if (!loadedPackages.has(package)) {
|
||||
toLoad.add(package);
|
||||
packages[package].forEach((subpackage) => {
|
||||
if (!loadedPackages.has(subpackage) && !toLoad.has(subpackage)) {
|
||||
queue.push(subpackage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
if (toLoad.size === 0) {
|
||||
resolve('No new packages to load');
|
||||
}
|
||||
|
||||
pyodide.monitorRunDependencies = (n) => {
|
||||
if (n === 0) {
|
||||
toLoad.forEach((package) => loadedPackages.add(package));
|
||||
delete pyodide.monitorRunDependencies;
|
||||
const packageList = Array.from(toLoad.keys()).join(', ');
|
||||
resolve(`Loaded ${packageList}`);
|
||||
}
|
||||
};
|
||||
|
||||
toLoad.forEach((package) => {
|
||||
let script = document.createElement('script');
|
||||
script.src = `${baseURL}${package}.js`;
|
||||
script.onerror = (e) => { reject(e); };
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
|
||||
// We have to invalidate Python's import caches, or it won't
|
||||
// see the new files. This is done here so it happens in parallel
|
||||
// with the fetching over the network.
|
||||
window.pyodide.runPython('import importlib as _importlib\n' +
|
||||
'_importlib.invalidate_caches()\n');
|
||||
});
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Loading Pyodide
|
||||
let wasmURL = `${baseURL}pyodide.asm.wasm`;
|
||||
let Module = {};
|
||||
window.Module = Module;
|
||||
|
||||
let wasm_promise = WebAssembly.compileStreaming(fetch(wasmURL));
|
||||
Module.instantiateWasm = (info, receiveInstance) => {
|
||||
wasm_promise.then(module => WebAssembly.instantiate(module, info))
|
||||
.then(instance => receiveInstance(instance));
|
||||
return {};
|
||||
};
|
||||
Module.filePackagePrefixURL = baseURL;
|
||||
Module.postRun = () => {
|
||||
delete window.Module;
|
||||
resolve();
|
||||
};
|
||||
|
||||
let data_script = document.createElement('script');
|
||||
data_script.src = `${baseURL}pyodide.asm.data.js`;
|
||||
data_script.onload = (event) => {
|
||||
let script = document.createElement('script');
|
||||
script.src = `${baseURL}pyodide.asm.js`;
|
||||
script.onload = () => {
|
||||
window.pyodide = pyodide(Module);
|
||||
window.pyodide.loadPackage = loadPackage;
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
};
|
||||
|
||||
document.head.appendChild(data_script);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Iodide-specific functionality, that doesn't make sense
|
||||
// if not using with Iodide.
|
||||
if (window.iodide !== undefined) {
|
||||
// Load the custom CSS for Pyodide
|
||||
let link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = `${baseURL}renderedhtml.css`;
|
||||
document.getElementsByTagName('head')[0].appendChild(link);
|
||||
|
||||
// Add a custom output handler for Python objects
|
||||
window.iodide.addOutputHandler({
|
||||
shouldHandle : (val) => {
|
||||
return (typeof val === 'function' && pyodide.PyProxy.isPyProxy(val));
|
||||
},
|
||||
|
||||
render : (val) => {
|
||||
let div = document.createElement('div');
|
||||
div.className = 'rendered_html';
|
||||
var element;
|
||||
if (val._repr_html_ !== undefined) {
|
||||
let result = val._repr_html_();
|
||||
if (typeof result === 'string') {
|
||||
div.appendChild(new DOMParser()
|
||||
.parseFromString(result, 'text/html')
|
||||
.body.firstChild);
|
||||
element = div;
|
||||
} else {
|
||||
element = result;
|
||||
}
|
||||
} else {
|
||||
let pre = document.createElement('pre');
|
||||
pre.textContent = val.toString();
|
||||
div.appendChild(pre);
|
||||
element = div;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
languagePluginLoader
|
||||
|
|
|
@ -6,6 +6,7 @@ from js import XMLHttpRequest
|
|||
|
||||
import io
|
||||
|
||||
|
||||
def open_url(url):
|
||||
"""
|
||||
Fetches a given *url* and returns a io.StringIO to access its contents.
|
||||
|
|
|
@ -5,18 +5,22 @@
|
|||
#include "js2python.h"
|
||||
#include "python2js.h"
|
||||
|
||||
int _pyproxy_has(int ptrobj, int idkey) {
|
||||
PyObject *pyobj = (PyObject *)ptrobj;
|
||||
PyObject *pykey = js2python(idkey);
|
||||
int result = PyObject_HasAttr(pyobj, pykey) ? hiwire_true(): hiwire_false();
|
||||
int
|
||||
_pyproxy_has(int ptrobj, int idkey)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
PyObject* pykey = js2python(idkey);
|
||||
int result = PyObject_HasAttr(pyobj, pykey) ? hiwire_true() : hiwire_false();
|
||||
Py_DECREF(pykey);
|
||||
return result;
|
||||
}
|
||||
|
||||
int _pyproxy_get(int ptrobj, int idkey) {
|
||||
PyObject *pyobj = (PyObject *)ptrobj;
|
||||
PyObject *pykey = js2python(idkey);
|
||||
PyObject *pyattr = PyObject_GetAttr(pyobj, pykey);
|
||||
int
|
||||
_pyproxy_get(int ptrobj, int idkey)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
PyObject* pykey = js2python(idkey);
|
||||
PyObject* pyattr = PyObject_GetAttr(pyobj, pykey);
|
||||
Py_DECREF(pykey);
|
||||
if (pyattr == NULL) {
|
||||
PyErr_Clear();
|
||||
|
@ -28,10 +32,12 @@ int _pyproxy_get(int ptrobj, int idkey) {
|
|||
return idattr;
|
||||
};
|
||||
|
||||
int _pyproxy_set(int ptrobj, int idkey, int idval) {
|
||||
PyObject *pyobj = (PyObject *)ptrobj;
|
||||
PyObject *pykey = js2python(idkey);
|
||||
PyObject *pyval = js2python(idval);
|
||||
int
|
||||
_pyproxy_set(int ptrobj, int idkey, int idval)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
PyObject* pykey = js2python(idkey);
|
||||
PyObject* pyval = js2python(idval);
|
||||
int result = PyObject_SetAttr(pyobj, pykey, pyval);
|
||||
Py_DECREF(pykey);
|
||||
Py_DECREF(pyval);
|
||||
|
@ -42,9 +48,11 @@ int _pyproxy_set(int ptrobj, int idkey, int idval) {
|
|||
return idval;
|
||||
}
|
||||
|
||||
int _pyproxy_deleteProperty(int ptrobj, int idkey) {
|
||||
PyObject *pyobj = (PyObject *)ptrobj;
|
||||
PyObject *pykey = js2python(idkey);
|
||||
int
|
||||
_pyproxy_deleteProperty(int ptrobj, int idkey)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
PyObject* pykey = js2python(idkey);
|
||||
|
||||
int ret = PyObject_DelAttr(pyobj, pykey);
|
||||
Py_DECREF(pykey);
|
||||
|
@ -56,9 +64,11 @@ int _pyproxy_deleteProperty(int ptrobj, int idkey) {
|
|||
return hiwire_undefined();
|
||||
}
|
||||
|
||||
int _pyproxy_ownKeys(int ptrobj) {
|
||||
PyObject *pyobj = (PyObject *)ptrobj;
|
||||
PyObject *pydir = PyObject_Dir(pyobj);
|
||||
int
|
||||
_pyproxy_ownKeys(int ptrobj)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
PyObject* pydir = PyObject_Dir(pyobj);
|
||||
|
||||
if (pydir == NULL) {
|
||||
return pythonexc2js();
|
||||
|
@ -67,7 +77,7 @@ int _pyproxy_ownKeys(int ptrobj) {
|
|||
int iddir = hiwire_array();
|
||||
Py_ssize_t n = PyList_Size(pydir);
|
||||
for (Py_ssize_t i = 0; i < n; ++i) {
|
||||
PyObject *pyentry = PyList_GetItem(pydir, i);
|
||||
PyObject* pyentry = PyList_GetItem(pydir, i);
|
||||
int identry = python2js(pyentry);
|
||||
hiwire_push_array(iddir, identry);
|
||||
hiwire_decref(identry);
|
||||
|
@ -77,21 +87,25 @@ int _pyproxy_ownKeys(int ptrobj) {
|
|||
return iddir;
|
||||
}
|
||||
|
||||
int _pyproxy_enumerate(int ptrobj) {
|
||||
int
|
||||
_pyproxy_enumerate(int ptrobj)
|
||||
{
|
||||
return _pyproxy_ownKeys(ptrobj);
|
||||
}
|
||||
|
||||
int _pyproxy_apply(int ptrobj, int idargs) {
|
||||
PyObject *pyobj = (PyObject *)ptrobj;
|
||||
int
|
||||
_pyproxy_apply(int ptrobj, int idargs)
|
||||
{
|
||||
PyObject* pyobj = (PyObject*)ptrobj;
|
||||
Py_ssize_t length = hiwire_get_length(idargs);
|
||||
PyObject *pyargs = PyTuple_New(length);
|
||||
PyObject* pyargs = PyTuple_New(length);
|
||||
for (Py_ssize_t i = 0; i < length; ++i) {
|
||||
int iditem = hiwire_get_member_int(idargs, i);
|
||||
PyObject *pyitem = js2python(iditem);
|
||||
PyObject* pyitem = js2python(iditem);
|
||||
PyTuple_SET_ITEM(pyargs, i, pyitem);
|
||||
hiwire_decref(iditem);
|
||||
}
|
||||
PyObject *pyresult = PyObject_Call(pyobj, pyargs, NULL);
|
||||
PyObject* pyresult = PyObject_Call(pyobj, pyargs, NULL);
|
||||
if (pyresult == NULL) {
|
||||
Py_DECREF(pyargs);
|
||||
return pythonexc2js();
|
||||
|
@ -109,6 +123,7 @@ EM_JS(int, pyproxy_new, (int ptrobj), {
|
|||
});
|
||||
|
||||
EM_JS(int, pyproxy_init, (), {
|
||||
// clang-format off
|
||||
Module.PyProxy = {
|
||||
getPtr: function(jsobj) {
|
||||
return jsobj['$$']['ptr'];
|
||||
|
@ -193,4 +208,5 @@ EM_JS(int, pyproxy_init, (), {
|
|||
};
|
||||
|
||||
return 0;
|
||||
// clang-format on
|
||||
});
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
// This implements the Javascript Proxy handler interface as defined here:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
||||
|
||||
int pyproxy_new(int obj);
|
||||
int pyproxy_init();
|
||||
int
|
||||
pyproxy_new(int obj);
|
||||
|
||||
int
|
||||
pyproxy_init();
|
||||
|
||||
#endif /* PYPROXY_H */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# flake8: noqa
|
||||
|
||||
"""
|
||||
"PYSTONE" Benchmark Program
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
#include "jsproxy.h"
|
||||
#include "pyproxy.h"
|
||||
|
||||
int pythonexc2js() {
|
||||
PyObject *type;
|
||||
PyObject *value;
|
||||
PyObject *traceback;
|
||||
int
|
||||
pythonexc2js()
|
||||
{
|
||||
PyObject* type;
|
||||
PyObject* value;
|
||||
PyObject* traceback;
|
||||
int no_traceback = 0;
|
||||
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
|
@ -18,17 +20,16 @@ int pythonexc2js() {
|
|||
int excval = -1;
|
||||
int exc;
|
||||
|
||||
if (type == NULL || type == Py_None ||
|
||||
value == NULL || value == Py_None) {
|
||||
if (type == NULL || type == Py_None || value == NULL || value == Py_None) {
|
||||
excval = hiwire_string_utf8((int)"No exception type or value");
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
PyObject *tbmod = PyImport_ImportModule("traceback");
|
||||
PyObject* tbmod = PyImport_ImportModule("traceback");
|
||||
if (tbmod == NULL) {
|
||||
PyObject *repr = PyObject_Repr(value);
|
||||
PyObject* repr = PyObject_Repr(value);
|
||||
if (repr == NULL) {
|
||||
excval = hiwire_string_utf8((int)"Could not get repr for exception");
|
||||
} else {
|
||||
|
@ -36,7 +37,7 @@ int pythonexc2js() {
|
|||
Py_DECREF(repr);
|
||||
}
|
||||
} else {
|
||||
PyObject *format_exception;
|
||||
PyObject* format_exception;
|
||||
if (traceback == NULL || traceback == Py_None) {
|
||||
no_traceback = 1;
|
||||
format_exception = PyObject_GetAttrString(tbmod, "format_exception_only");
|
||||
|
@ -44,24 +45,26 @@ int pythonexc2js() {
|
|||
format_exception = PyObject_GetAttrString(tbmod, "format_exception");
|
||||
}
|
||||
if (format_exception == NULL) {
|
||||
excval = hiwire_string_utf8((int)"Could not get format_exception function");
|
||||
excval =
|
||||
hiwire_string_utf8((int)"Could not get format_exception function");
|
||||
} else {
|
||||
PyObject *pylines;
|
||||
PyObject* pylines;
|
||||
if (no_traceback) {
|
||||
pylines = PyObject_CallFunctionObjArgs
|
||||
(format_exception, type, value, NULL);
|
||||
pylines =
|
||||
PyObject_CallFunctionObjArgs(format_exception, type, value, NULL);
|
||||
} else {
|
||||
pylines = PyObject_CallFunctionObjArgs
|
||||
(format_exception, type, value, traceback, NULL);
|
||||
pylines = PyObject_CallFunctionObjArgs(
|
||||
format_exception, type, value, traceback, NULL);
|
||||
}
|
||||
if (pylines == NULL) {
|
||||
excval = hiwire_string_utf8((int)"Error calling traceback.format_exception");
|
||||
excval =
|
||||
hiwire_string_utf8((int)"Error calling traceback.format_exception");
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
goto exit;
|
||||
} else {
|
||||
PyObject *newline = PyUnicode_FromString("");
|
||||
PyObject *pystr = PyUnicode_Join(newline, pylines);
|
||||
PyObject* newline = PyUnicode_FromString("");
|
||||
PyObject* pystr = PyUnicode_Join(newline, pylines);
|
||||
printf("Python exception:\n");
|
||||
printf("%s\n", PyUnicode_AsUTF8(pystr));
|
||||
excval = python2js(pystr);
|
||||
|
@ -74,7 +77,7 @@ int pythonexc2js() {
|
|||
Py_DECREF(tbmod);
|
||||
}
|
||||
|
||||
exit:
|
||||
exit:
|
||||
Py_XDECREF(type);
|
||||
Py_XDECREF(value);
|
||||
Py_XDECREF(traceback);
|
||||
|
@ -86,15 +89,17 @@ int pythonexc2js() {
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int is_type_name(PyObject *x, const char *name) {
|
||||
PyObject *x_type = PyObject_Type(x);
|
||||
static int
|
||||
is_type_name(PyObject* x, const char* name)
|
||||
{
|
||||
PyObject* x_type = PyObject_Type(x);
|
||||
if (x_type == NULL) {
|
||||
// If we can't get a type, that's probably ok in this case...
|
||||
PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *x_type_name = PyObject_Repr(x_type);
|
||||
PyObject* x_type_name = PyObject_Repr(x_type);
|
||||
Py_DECREF(x_type);
|
||||
|
||||
int result = (PyUnicode_CompareWithASCIIString(x_type_name, name) == 0);
|
||||
|
@ -103,7 +108,9 @@ static int is_type_name(PyObject *x, const char *name) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int python2js(PyObject *x) {
|
||||
int
|
||||
python2js(PyObject* x)
|
||||
{
|
||||
if (x == Py_None) {
|
||||
return hiwire_undefined();
|
||||
} else if (x == Py_True) {
|
||||
|
@ -124,25 +131,25 @@ int python2js(PyObject *x) {
|
|||
return hiwire_double(x_double);
|
||||
} else if (PyUnicode_Check(x)) {
|
||||
Py_ssize_t length;
|
||||
char *chars = PyUnicode_AsUTF8AndSize(x, &length);
|
||||
char* chars = PyUnicode_AsUTF8AndSize(x, &length);
|
||||
if (chars == NULL) {
|
||||
return pythonexc2js();
|
||||
}
|
||||
return hiwire_string_utf8_length((int)(void *)chars, length);
|
||||
return hiwire_string_utf8_length((int)(void*)chars, length);
|
||||
} else if (PyBytes_Check(x)) {
|
||||
char *x_buff;
|
||||
char* x_buff;
|
||||
Py_ssize_t length;
|
||||
if (PyBytes_AsStringAndSize(x, &x_buff, &length)) {
|
||||
return pythonexc2js();
|
||||
}
|
||||
return hiwire_bytes((int)(void *)x_buff, length);
|
||||
return hiwire_bytes((int)(void*)x_buff, length);
|
||||
} else if (JsProxy_Check(x)) {
|
||||
return JsProxy_AsJs(x);
|
||||
} else if (PyList_Check(x) || is_type_name(x, "<class 'numpy.ndarray'>")) {
|
||||
int jsarray = hiwire_array();
|
||||
size_t length = PySequence_Size(x);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
PyObject *pyitem = PySequence_GetItem(x, i);
|
||||
PyObject* pyitem = PySequence_GetItem(x, i);
|
||||
if (pyitem == NULL) {
|
||||
// If something goes wrong converting the sequence (as is the case with
|
||||
// Pandas data frames), fallback to the Python object proxy
|
||||
|
@ -191,6 +198,8 @@ int python2js(PyObject *x) {
|
|||
}
|
||||
}
|
||||
|
||||
int python2js_init() {
|
||||
int
|
||||
python2js_init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,16 +9,20 @@
|
|||
/** Convert the active Python exception into a Javascript Error object.
|
||||
* \return A Javascript Error object
|
||||
*/
|
||||
int pythonexc2js();
|
||||
int
|
||||
pythonexc2js();
|
||||
|
||||
/** Convert a Python object to a Javascript object.
|
||||
* \param The Python object
|
||||
* \return The Javascript object -- might be an Error object in the case of an exception.
|
||||
* \return The Javascript object -- might be an Error object in the case of an
|
||||
* exception.
|
||||
*/
|
||||
int python2js(PyObject *x);
|
||||
int
|
||||
python2js(PyObject* x);
|
||||
|
||||
/** Set up the global state for this module.
|
||||
*/
|
||||
int python2js_init();
|
||||
int
|
||||
python2js_init();
|
||||
|
||||
#endif /* PYTHON2JS_H */
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
#include "runpython.h"
|
||||
|
||||
#include <emscripten.h>
|
||||
#include <Python.h>
|
||||
#include <emscripten.h>
|
||||
#include <node.h> // from Python
|
||||
|
||||
#include "python2js.h"
|
||||
#include "hiwire.h"
|
||||
#include "python2js.h"
|
||||
|
||||
extern PyObject *globals;
|
||||
extern PyObject* globals;
|
||||
|
||||
static int is_whitespace(char x) {
|
||||
static int
|
||||
is_whitespace(char x)
|
||||
{
|
||||
switch (x) {
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int _runPython(char *code) {
|
||||
char *last_line = code;
|
||||
int
|
||||
_runPython(char* code)
|
||||
{
|
||||
char* last_line = code;
|
||||
while (*last_line != 0) {
|
||||
++last_line;
|
||||
}
|
||||
|
@ -39,11 +43,13 @@ int _runPython(char *code) {
|
|||
// Find the last non-whitespace-only line since that will provide the result
|
||||
// TODO: This way to find the last line will probably break in many ways
|
||||
last_line--;
|
||||
for (; last_line != code && is_whitespace(*last_line); last_line--) {}
|
||||
for (; last_line != code && *last_line != '\n'; last_line--) {}
|
||||
for (; last_line != code && is_whitespace(*last_line); last_line--) {
|
||||
}
|
||||
for (; last_line != code && *last_line != '\n'; last_line--) {
|
||||
}
|
||||
|
||||
int do_eval_line = 1;
|
||||
struct _node *co;
|
||||
struct _node* co;
|
||||
co = PyParser_SimpleParseStringFlags(last_line, Py_eval_input, cf.cf_flags);
|
||||
if (co == NULL) {
|
||||
do_eval_line = 0;
|
||||
|
@ -51,7 +57,7 @@ int _runPython(char *code) {
|
|||
}
|
||||
PyNode_Free(co);
|
||||
|
||||
PyObject *ret;
|
||||
PyObject* ret;
|
||||
if (do_eval_line == 0 || last_line != code) {
|
||||
if (do_eval_line) {
|
||||
*last_line = 0;
|
||||
|
@ -65,16 +71,16 @@ int _runPython(char *code) {
|
|||
}
|
||||
|
||||
switch (do_eval_line) {
|
||||
case 0:
|
||||
Py_INCREF(Py_None);
|
||||
ret = Py_None;
|
||||
break;
|
||||
case 1:
|
||||
ret = PyRun_StringFlags(last_line, Py_eval_input, globals, globals, &cf);
|
||||
break;
|
||||
case 2:
|
||||
ret = PyRun_StringFlags(last_line, Py_file_input, globals, globals, &cf);
|
||||
break;
|
||||
case 0:
|
||||
Py_INCREF(Py_None);
|
||||
ret = Py_None;
|
||||
break;
|
||||
case 1:
|
||||
ret = PyRun_StringFlags(last_line, Py_eval_input, globals, globals, &cf);
|
||||
break;
|
||||
case 2:
|
||||
ret = PyRun_StringFlags(last_line, Py_file_input, globals, globals, &cf);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
|
@ -87,7 +93,8 @@ int _runPython(char *code) {
|
|||
}
|
||||
|
||||
EM_JS(int, runpython_init, (), {
|
||||
Module.runPython = function (code) {
|
||||
Module.runPython = function(code)
|
||||
{
|
||||
var pycode = allocate(intArrayFromString(code), 'i8', ALLOC_NORMAL);
|
||||
var idresult = Module.__runPython(pycode);
|
||||
jsresult = Module.hiwire_get_value(idresult);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/** The primary entry point function that runs Python code.
|
||||
*/
|
||||
|
||||
|
||||
int runpython_init();
|
||||
int
|
||||
runpython_init();
|
||||
|
||||
#endif /* RUNPYTHON_H */
|
||||
|
|
|
@ -18,7 +18,7 @@ import math
|
|||
|
||||
from matplotlib.backends import backend_agg
|
||||
from matplotlib.backend_bases import _Backend
|
||||
from matplotlib import backend_bases, interactive, _png
|
||||
from matplotlib import backend_bases, interactive
|
||||
|
||||
from js import document
|
||||
from js import window
|
||||
|
@ -130,14 +130,15 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
|
|||
rubberband.setAttribute('width', width)
|
||||
rubberband.setAttribute('height', height)
|
||||
rubberband.setAttribute(
|
||||
'style', 'position: absolute; left: 0; top: 0; z-index: 0; outline: 0;' +
|
||||
'width: {}px; height: {}px'.format(
|
||||
'style', 'position: absolute; left: 0; top: 0; z-index: 0; ' +
|
||||
'outline: 0; width: {}px; height: {}px'.format(
|
||||
width / self._ratio, height / self._ratio)
|
||||
)
|
||||
# Canvas must have a "tabindex" attr in order to receive keyboard events
|
||||
# Canvas must have a "tabindex" attr in order to receive keyboard
|
||||
# events
|
||||
rubberband.setAttribute('tabindex', '0')
|
||||
# Event handlers are added to the canvas "on top", even though most of the
|
||||
# activity happens in the canvas below.
|
||||
# Event handlers are added to the canvas "on top", even though most of
|
||||
# the activity happens in the canvas below.
|
||||
rubberband.addEventListener('mousemove', self.onmousemove)
|
||||
rubberband.addEventListener('mouseup', self.onmouseup)
|
||||
rubberband.addEventListener('mousedown', self.onmousedown)
|
||||
|
@ -146,7 +147,7 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
|
|||
rubberband.addEventListener('keyup', self.onkeyup)
|
||||
rubberband.addEventListener('keydown', self.onkeydown)
|
||||
context = rubberband.getContext('2d')
|
||||
context.strokeStyle = '#000000';
|
||||
context.strokeStyle = '#000000'
|
||||
context.setLineDash([2, 2])
|
||||
canvas_div.appendChild(rubberband)
|
||||
|
||||
|
@ -175,13 +176,13 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
|
|||
# Copy the image buffer to the canvas
|
||||
width, height = self.get_width_height()
|
||||
canvas = self.get_element('canvas')
|
||||
if canvas == None:
|
||||
if canvas is None:
|
||||
return
|
||||
image_data = ImageData.new(
|
||||
self.buffer_rgba(),
|
||||
width, height);
|
||||
ctx = canvas.getContext("2d");
|
||||
ctx.putImageData(image_data, 0, 0);
|
||||
width, height)
|
||||
ctx = canvas.getContext("2d")
|
||||
ctx.putImageData(image_data, 0, 0)
|
||||
finally:
|
||||
self.figure.dpi = orig_dpi
|
||||
self._idle_scheduled = False
|
||||
|
@ -244,7 +245,8 @@ class FigureCanvasWasm(backend_agg.FigureCanvasAgg):
|
|||
}
|
||||
|
||||
def set_cursor(self, cursor):
|
||||
self.get_element('rubberband').style.cursor = self._cursor_map.get(cursor, 0)
|
||||
self.get_element('rubberband').style.cursor = \
|
||||
self._cursor_map.get(cursor, 0)
|
||||
|
||||
# http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
|
||||
_SHIFT_LUT = {
|
||||
|
@ -447,7 +449,8 @@ class NavigationToolbar2Wasm(backend_bases.NavigationToolbar2):
|
|||
button = document.createElement('button')
|
||||
button.classList.add('fa')
|
||||
button.classList.add(_FONTAWESOME_ICONS[image_file])
|
||||
button.addEventListener('click', getattr(self, name_of_method))
|
||||
button.addEventListener(
|
||||
'click', getattr(self, name_of_method))
|
||||
div.appendChild(button)
|
||||
|
||||
for format, mimetype in sorted(list(FILE_TYPES.items())):
|
||||
|
|
|
@ -5,12 +5,15 @@ An implementation of the standard library webbrowser module to open webpages.
|
|||
Since we're already running a webbrowser, it's really simple...
|
||||
"""
|
||||
|
||||
|
||||
def open(url, new=0, autoraise=True):
|
||||
from js import window
|
||||
window.open(url, "_blank")
|
||||
|
||||
|
||||
def open_new(url):
|
||||
return open(url, 1)
|
||||
|
||||
|
||||
def open_new_tab(url):
|
||||
return open(url, 2)
|
||||
|
|
Loading…
Reference in New Issue