Commit 7c0457ce authored by Michael Droettboom's avatar Michael Droettboom

Add linting

parent 11a601f5
......@@ -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" }}
......
---
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
...
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_size = 2
indent_style = space
[Makefile]
indent_style = tab
\ No newline at end of file
......@@ -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
......
......@@ -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;
}
#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), {
......
......@@ -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 */
......@@ -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 */
#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 __foo2(double x, double y) {
void
__foo(double x)
{}
}
void __foo3(double x, double y, double z) {
void
__foo2(double x, double y)
{}
}
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 */
This diff is collapsed.
......@@ -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 */
#! /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 */
#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)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment