PyPy.js: A fast, compliant Python implementation for the web
pypyjs.org
pypyjs.org
> We have the following major components in the PyPy repo:
>> An "emscripten" build platform definition, which teaches pypy's rpython toolchain how to compile things with emscripten: ./deps/pypy/rpython/translator/platform/emscripten_platform/.
>> An rpython JIT backend that emits asmjs at runtime: ./deps/pypy/rpython/jit/backend/asmjs/.
>> A "js" builtin module for the resulting interperter, to allow interaction with the host javascript environment: ./deps/pypy/pypy/module/js/.
>Along with these wrappers to help working with the resulting interpreter:
>> A wrapper to load up the compiled VM and expose it via a nice javascript API: ./lib/pypy.js.
>> A script for bundling python modules into an indexed format that can be easily loaded into the browser: ./tools/module_bundler.py.
In https://github.com/rfk/pypy/blob/master/rpython/jit/backend/... alone, there are 2887 lines of custom Python code to emit asm.js for function and block JITing.
And at 3.26 seconds to initialize from cache on a 4-year-old machine, 5MB gzipped (not too much worse than your average high-quality gif) and only 1.5x slower than CPython... this is actually approaching viable if you needed to run Python business logic in the browser. Which I never thought I would see.
https://www.destroyallsoftware.com/talks/the-birth-and-death...
It is still very very efficient.
I'm not sure what this means, but if you mean that Firefox doesn't cache compiled asm.js code, that's not true. It does [1].
[1]: https://blog.mozilla.org/luke/2014/01/14/asm-js-aot-compilat...
By the way, is RPython a nice language to program in?
EDIT: Writing it is more restricted than normal Python, so you have to think about what you do (especially type hints, to make sure it gets what type your variables are) and the long feedback cycles due to compile time are annoying, but still very comfortable. And for building interpreters, the more or less "free" JIT is magic :)
Looking through that list it doesn't look dreadful. There are a couple of things that jump out though - you can't use kwargs in function definitions which is probably used quite a lot in dynamic settings.
Eg in Python one might do (warning; crazy, contrived example):
def create_thing(**kwargs):
thing = dict(id=gen_id())
thing['other_data'] = kwargs
return thing
thing = create_thing(name='name', foo='bar')
You could avoid it, and generally in Python you're better off being explicit about everything. But it's definitely a feature that gets used a fair amount, especially in libraries where you don't explicitly know what the api call takes concerning user data.An easy (more explicit) workaround would be:
def create_thing(other_data=None):
thing = dict(id=gen_id())
thing['other_data'] = other_data or {}
return thing
create_thing(dict(name='name', foo='bar'))
It's just a little more work for the calling code.Not really, if only for the insane compile times. The PyPy authors also heavily discourage using it except for interpreters.
It's a nice language to develop VMs in, it's a terrible language to do general-purpose programming in.
Thank you for the answers
I also wish github was up so I could look at the benchmark code - startup looks much faster with empython, but I'd like to know how much slower interpreting would be.
So Python is a bad candidate, but there are better candidates out there. For example, jsofocaml (using OCaml in the browser) looks quite promising.
In the end, we need a lightweight yet properly defined and highlevel language, and the ML languages as well as the LISP languages are great candidates for that.
Furthermore, Purescript's FFI is really nice to use and it's really easy to bind to existing javascript libraries.
PureScript is community is nice and active. They are also discussing a lot with the `virtual-dom` guys to bring react/om/mercury-like functionality to purescript [0] and it's quite freakin awesome.
Seriously I'd take purescript for javascript any day. I think it's great that we FP folks can finally do frontend dev :-)
On the flip side, with the state of libraries and all, it's provided me with a real incentive to get involved in open source, by having to contribute patches to said libraries and getting actively involved in general discussion.
Edit:
Just so I don't come off as mostly negative, I do enjoy having purescript as another statically typed option on the client side with close semantics to javascript. It's also been nice having a some kind of parsec like library on the client side (purescript-parsing), which was the main reason I chose purescript for this project in the first place.
A slightly less-hellish but still annoying problem is that I often poke at things directly from the console when bugs happen, and this helps me a lot in debugging. However poking at the console requires using JavaScript, which is fine, but it would drive me nuts to have to code in one language (e.g. CoffeeScript, TypeScript, Python) and debug in another (JavaScript) and switch my brain back and forth every few minutes. So I've ended up largely sticking with writing code directly in JavaScript.
Any good solutions to this? Are there replacements to the Chrome JavaScript console that supports those other languages?
Even lua would be a joy!
I honestly don't see how we can justify the cost of adding Lua to browsers. I see the merit of Lua-to-JS compilers (existing codebases or sheer love of the syntax), but built-in?
Lua 5.3 has both integer and floating-point types.
This applies equally to any language.
Direct link to answer: https://youtu.be/PiBfOFqDIAI?t=1611
It's true though that getting even two major browser vendors to agree on supporting another scripting language in addition to JS, is really really hard. I don't see it happening unless Nadella's "Really Good, Honest! (TM)" Microsoft makes some sort of grand gesture towards Google or (more likely) Mozilla.
Python is also only just starting to explore optional typing which is obviously a prime feature of Dart and JS derivatives like TypeScript.
Heck, there are existing python minification tools.
- Let there be pojs landing page
- Download pypy.js in the background
- Run python code
- Dance with Glee!
Python was one of those languages. You could download an ActivePython distribution and start being able to run python in your web page with a <script language="PythonScript"> tag.
I'm not sure if this still works in current IE versions. It might.
Also PyPy is the right choice as the basis for this (as opposed to CPython) because its ecosystem is generally more "pure" Python than CPython's. C Extensions would only get in the way.
Only for the first time loading it.
It would be great if some big organization (looks at Google) hosts the "standard" version of the file, much like jquery, so that it would be cached and ready to be used on the local machine most of the time.
How is the JS model accessed?
It makes me want to gouge my eyes out, but it's not really that hard to get productive in. CoffeeScript is even better, if you aren't averse to adding another dependency on top of everything else.
Pyjamas was based on GWT, right? So, a Java Framework translated to Python. It's as nice as running a pack of deer on a road with a truck.
Awful
This will probably never happen, but I can dream.
I haven't had the time to try it yet, but maybe it'll suit your needs ;)
self.$popup = $('#' + containerId).addClass('pop-up').mouseout(def():
self.hide()
) import js
js.eval("console.log(\"hi!\")") import js
js.globals.console.log('hi!') import js
js.globals.console.log('hi!'*5) import js
>>> "globals" in dir(js)
True
>>> "console" in dir(js.globals)
False
>>> js
<module 'js' (built-in)>
>>> js.globals.console
<js.Object handle=14>
So apparently introspection doesn't quite work with the wrapped js. Also, if you try: "[ i for i in js.globals]" (or equivalently iterate/loop over the globals-object) - the whole repl/tab hangs.Not really an issue for running business logic in the browser, but if this was a full python repl-interface (with ipython support!) to the whole browser DOM -- that'd be a fantastic tool.
Welcome to PyPy.js!
>>> import js
>>> "console" in js.globals
True
>>> "console" in dir(js.globals)
False js.eval('var div = document.createElement("div"); div.style.width = "100px"; div.style.height = "100px"; div.style.background = "red"; div.style.color = "white"; div.innerHTML = "Hello"; document.body.appendChild(div);');
manages to append a div.--
Directly modifying document.body.innerHTML in any way seems to hang it. Both:
js.eval('document.body.innerHTML += "<div></div>";');
js.globals.document.body.innerHTML += "<div></div>"
Cause it to hang, though the javascript console shows it was added (or using an img tag instead).(ChromeOS v43 beta)
import js
jq = js.eval("$")
first_line = jq(jq(".container p")[0])
first_line.text("jQuery was here") import js
c = js.globals.document.createElement("canvas")
js.globals.document.body.appendChild(c)
ctx = c.getContext("2d")
ctx.fillRect(10, 10, 10, 10)
Edit: Here is a simple animation: import js
import math
import time
c = js.globals.document.createElement("canvas")
js.globals.document.body.appendChild(c)
ctx = c.getContext("2d")
def render():
ctx.clearRect(0, 0, c.width, c.height)
t = time.time()
ctx.fillRect(20+math.sin(t*10)*10, 20+math.cos(t*10)*10, 10, 10)
js.globals.window.setInterval(render, 20)
Here's a version you can paste in properly: http://pastebin.com/raw.php?i=67GadSUV >>> import js
... c = js.globals.document.createElement("canvas")
...
debug: OperationError:
debug: operror-type: SyntaxError
debug: operror-value: ('EOL while scanning string literal', ('c callback', 1, 12, "r = c.push('import js\n", 0))
debug: OperationError:
debug: operror-type: KeyError
debug: operror-value: 'r'
And then the input window hangs. Strangely enough, if I type it in instead, it's okay.(ChromeOS v43 beta-channel)
import js
c = js.globals.document.createElement("canvas")
and not the pastebin.
The pastebin works for me, but only the first time. Subsequent runs result in: <RuntimeError object at 0x15d648>
RPython traceback:
...
Fatal RPython error:I guess these things will take a while to shake out, but I'd imagine a python-in-browser-api PEP at some point.
asm.js is a weird hack that lives in a totally different world than actual browser APIs (e.g. the DOM), and you have to emulate your entire runtime and environment to get anything useful, which means your binary is going to be huge (as in this example, but similar things apply).
Emulating better semantics than JS based on JS usually leaves you in this uncanny valley where you either trade off performance and size for nicer semantics (e.g. killing the null/undefined dichotomy, or 64 bit integer math), or you end up with odd semantics that don't quite fit the language you're compiling from, or a mix of both, which is a usability disaster.
So the only real chance to improve on the state of JS is being a syntactical shim on top of JS and help users with better syntax, static analysis, and compile time tooling. That'd be TypeScript.
Or CoffeeScript. Or Dart. Or this. In fact, here's a whole big long list of other languages. Most of which don't use the asm.js "weird hack".
https://github.com/jashkenas/coffeescript/wiki/List-of-langu...
developers hate him!
>>> from datetime import datetime
>>> datetime.now()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/lib/pypyjs/lib_pypy/datetime.py", line 1548, in now
return cls.fromtimestamp(t, tz)
File "/lib/pypyjs/lib_pypy/datetime.py", line 1522, in fromtimestamp
result = cls(y, m, d, hh, mm, ss, us, tz)
File "/lib/pypyjs/lib_pypy/datetime.py", line 1459, in __new__
hour, minute, second, microsecond)
File "/lib/pypyjs/lib_pypy/datetime.py", line 312, in _check_time_fields
raise ValueError('microsecond must be in 0..999999', microsecond)
ValueError: ('microsecond must be in 0..999999', 1716000) >>> from datetime import datetime
>>> datetime.now()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/lib/pypyjs/lib_pypy/datetime.py", line 1548, in now
return cls.fromtimestamp(t, tz)
File "/lib/pypyjs/lib_pypy/datetime.py", line 1511, in fromtimestamp
us = _round(frac * 1e6)
File "/lib/pypyjs/lib_pypy/datetime.py", line 28, in _round
return int(_math.floor(x + 0.5) if x >= 0.0 else _math.ceil(x - 0.5))
ValueError: cannot convert float NaN to integer(However, it took about 10 seconds to execute. Maybe that's the network I'm on, but even so...)
If it did (and it has big ramifications for how much of "python" (for some definition of "python" that includes most of the standard library) works. Eg sockets, interacting with some sort of "local" "file-system" etc) one could (this is handy if working on windows, and running python via cmd-r python.exe):
import pip
# pip.main expects a list of arguments, hence .split()
pip.main("install ipython".split())
# Only needed first
# time, as it installs ipython under site-packages.
# Only works if the user has write access, obviously
import IPython
IPython.start_ipython()I'd be happy enough with serving .py files with the exact same restrictions and privileges that JS libraries have now.
Why? You're assuming a lot of things about a hypothetical implementation that is going to have heavy restrictions on in anyway since it's running in the javascript sandbox.
If we're going to run everything in the browser, why use javascript as the low-level language that stuff compiles to?
I know portability and existing standards are a limitation, but those can be influenced by the 3 (?) major browsers if needed.
I think asm.js is an awesome cute little thing, but the fact that it's taken seriously is worrisome to me.
Am I completely crazy here?
Tried python server-side, mod_python and got lots of issues with formatting. Not syntax or mixed tab/spaces but one-off spacing errors. I realised then, Python used this way has problems. Could be fixed though.
I don't like the fact python code stops working randomly if I write it in one environment then touch (edit) in another. Never have this problem with C or JS.
I've never ( read 99.999% of the time I've performed the task ) had issues with Python formatting that weren't my own fault, everyone makes mistakes after all. I routinely edit the same Python files in Vim, Nano, Sublime Text, Atom, and PyCharm, and even jumping between all those editors, they have never "damaged" the formatting and created syntax errors in my code.
I can only surmise that some of the things you used or even just your vim config was setup poorly for Python work.
Do you routinely change OS?
[0] - http://opalrb.org
"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://10.30.229.27:15871/cgi-bin/blockpage.cgi?ws-session=1.... This can be fixed by moving the resource to the same domain or enabling CORS."
Firefox 37.0.1
Although I appreciate that this isn't technically "written in JavaScript" but it follows the principle.
... return x,y
debug: OperationError:
debug: operror-type: SyntaxError
debug: operror-value: ('EOL while scanning string literal', ('c callback', 1, 12, "r = c.push('def foo(x,y):\n", 0))
>>>
It boils down to the argument that "if there is no existing Python code relying on Python 2 semantics, why even bother making a Python 2 version, why not skip straight to Python 3 and not introduce the switching problem later?" There's a small matter of the Python 3 version not being the prime target of PyPy but they are updating it and progressing it forward so it's not any kind of roadblock just a little less than perfect.
Also python implementations that run in the browser.
[1] skulpt.org [2] brython.info
Curious. Interesting tech. But hardly practical.