Giter Club home page Giter Club logo

pythonjs's Introduction

Introduction

PythonJS is a transpiler written in Python that converts a python like language into fast JavaScript. It also includes experimental backends that translate to: Dart, Lua, CoffeeScript, and Go.

Syntax Documentation

Go backend

The Go backend uses a fully typed subset of Python, mixed with extra syntax inspired by Golang to output Go programs that can be compiled to native executeables, or translated to JavaScript using GopherJS.

Syntax Documentation

Getting Started

PythonJS can be run with regular Python, or fully self-hosted within NodeJS using Empythoned.

To get started, you have two options:

  1. install NodeJS, python-js package, and write a build script.

  2. or install Python2 and use translator.py from this repo directly.

  3. Installing NodeJS Package


You can quickly get started with the stable version of PythonJS by installing the NodeJS package, and writing a build script in javascript to compile your python scripts to javascript. (Python2.7 is not required)

npm install python-js

NodeJS Quick Example

var pythonjs = require('python-js');
var pycode = "a = []; a.append('hello'); a.append('world'); print(a)";
var jscode = pythonjs.translator.to_javascript( pycode );
eval( pythonjs.runtime.javascript + jscode );

Example Projects

The example projects below, require the NodeJS python-js package.

https://github.com/PythonJS/pythonjs-demo-server-nodejs

https://github.com/PythonJS/pypubjs

  1. translator.py

If you want to run the latest version of the translator, you will need to install Python2.7 and git clone this repo. (the NodeJS package above is not required) Then, to translate your python script, directly run the translator.py script in the "pythonjs" directory. You can give it a list of python files to translate at once.
It will output the translation to stdout. The default output type is JavaScript.
An html file can also be used as input, python code inside a script tag: <script type="text/python"> will be converted into JavaScript.

Usage::

translator.py [--help|--go|--dart|--coffee|--lua|--no-wrapper|--analyzer] file.py

Examples::

cd pythonjs
./translator.py myscript.py > myscript.js
./translator.py myapp.html > app.html

The option --no-wrapper will output the raw JavaScript, by default the output is wrapped as a requirejs module.

The option --analyzer requires the Dart SDK is installed to your home directory: ~/dart-sdk, if this option is used then your script is also translated using the dart backend and fed to dartanalyzer which will perform static analysis of your code. Dartanalyzer is able to catch many types of errors, like: missing functions, invalid names, calling a function with the wrong argument types. The quality of the analysis will depend on how much type information can be inferred from your code, combined with the variables you have manually typed. If dartanalyzer detects an error in your code, translation will abort, and debugging information is printed.

Speed

PythonJS gives you the option to optimize your program for speed with a new syntax for static typing, in some cases this results in code that is 20X faster. A variable can be statically typed as: int, float, long, str, list, or dict.
The translator then uses this type information to speed up runtime checks and method calls. In the example below x and y are typed as int.

def f(x,y):
	int x
	int y
	return x+y

The int type is accurate up to 53bits, if you need true 64bit integer math you can use the long type. Note using long requires the Long.js library.

You can further optimize your code with pythonjs.configure or special with statements that mark sections of the code as less dynamic.

N-Body benchmark

nbody

More benchmarks: Richards, n-body, Pystone, Fannkuch

GPU Translation

A Python typed subset can be translated to a GLSL fragment shader to speed up math on large arrays. GPU Documentation

Supported Features

####Language Overview

classes
multiple inheritance
operator overloading
function and class decorators
getter/setter function decorators
list comprehensions
yield (generator functions)
regular and lambda functions
function calls with *args and **kwargs

####Language Keywords

global, nonlocal
while, for, continue, break
if, elif, else
try, except, raise
def, lambda
new, class
from, import, as
pass, assert
and, or, is, in, not
return, yield

####HTML DOM: for item in iterable NodeList FileList ClientRectList DOMSettableTokenList DOMStringList DataTransferItemList HTMLCollection HTMLAllCollection SVGElementInstanceList SVGNumberList SVGTransformList

####Operator Overloading

__getattr__
__getattribute__
__getitem__
__setitem__
__call__
__iter__
__add__
__mul__

####builtins

dir
type
hasattr
getattr
setattr
issubclass
isinstance
dict
list
tuple
int
float
str
round
range
sum
len
map
filter
min
max
abs
ord
chr
open  (nodejs only)

####List

list.append
list.extend
list.remove
list.insert
list.index
list.count
list.pop
list.__len__
list.__contains__
list.__getitem__
list.__setitem__
list.__iter__
list.__getslice__

####Set

set.bisect
set.difference
set.intersection
set.issubset

####String

str.split
str.splitlines
str.strip
str.startswith
str.endswith
str.join
str.upper
str.lower
str.index
str.find
str.isdigit
str.format
str.__iter__
str.__getitem__
str.__len__
str.__getslice__

####Dict

dict.copy
dict.clear
dict.has_key
dict.update
dict.items
dict.keys
dict.get
dict.set
dict.pop
dict.values
dict.__contains__
dict.__iter__
dict.__len__
dict.__getitem__
dict.__setitem__

####Libraries

time.time
time.sleep
math.sin
math.cos
math.sqrt
array.array
os.path.dirname
bisect.bisect
random.random
threading.start_new_thread

#####Libraries (nodejs only) tempfile.gettempdir sys.stdin sys.stdout sys.stderr sys.argv sys.exit subprocess.Popen subprocess.call os.path.*


Regression Tests

The best way to see what features are currently supported with each of the backends is to run the automated regression tests in PythonJS/regtests. To test all the backends you need to install NodeJS, CoffeeScript, and Dart2JS. You should download the Dart SDK, and make sure that the executeable dart2js is in ~/dart-sdk/bin/

####Run Regression Tests

cd PythonJS/regtests
./run.py

Community

https://groups.google.com/forum/#!forum/pythonjs

irc freenode::

#pythonjs

pythonjs.configure

The special function call pythonjs.configure can be inserted anywhere in your code to turn off an on dynamic features of the language.

If the option direct_keys is True then dictionary key lookups are done directly (faster), objects can not be used as keys, only strings and numbers can then be used as dictionary keys.

The option direct_operator controls operator overloading for a given operator: '+', '*'. If '+' is declared a direct operator then __add__ overload methods are not called, the operands are always assumed to be compatible with javascript addition.

The option runtime_exceptions if False disables extra runtime checking of expressions and assignments, note this is always False in javascript mode.

pythonjs.configure(
	javascript=True/False,          ## default False
	runtime_exceptions=True/False,  ## default True
	direct_keys=True/False,         ## default False
	direct_operator=string          ## default 'None'
)

Gotchas

  1. in a dictionary number keys will be converted to strings. In the example below the key 100 and "100" are the same key.
a = {"100": 'X'}
a[ 100 ] = 'Y'
  1. The calling context of this must be taken into account when using fast javascript mode, code that comes after: pythonjs.configure(javascript=True) or is inside a with javascript: block. When in javascript mode, passing a method as a callback, or setting it as an attribute on another object, requires you call f.bind(self) to ensure that self within the method points to the class instance. This is not required when using classes defined normal mode, because the this calling context is automatically managed. Note: you can use the special -> syntax in place of the attribute operator . to call bind automatically.
class A:
	def method(self):
		print(self)

a = A()

with javascript:
	class B:
		def method(self):
			print(self)

	b = B()
	a.b_method1 = b.method
	a.b_method2 = b.method.bind(b)
	a.b_method3 = b->method

	a.method()     ## OK: prints a
	a.b_method1()  ## FAILS: prints a, should have printed b
	a.b_method2()  ## OK: prints b
	a.b_method3()  ## OK: prints b

	b.a_method = a.method
	b.a_method()   ## OK: prints a

  1. When using direct operators, builtins are also affected. List + list will no longer return a new array of items from both lists. String * N will no longer return the string multipled by the number.
a = [1,2] + [3,4]  ## OK: a is [1,2,3,4]
pythonjs.configure(direct_operator="+")
b = [1,2] + [3,4]  ## FAILS

c = "HI" * 2  ## OK: c is "HIHI"
pythonjs.configure(direct_operator="*")
d = "HI" * 2  ## FAILS

  1. The syntax from mymodule import * allows you to import another python script from the same folder, but both mymodule and the parent will share the same namespace, mymodule can use global variables defined in the parent.

  2. Using tuples as keys in a dict is allowed, the tuple may contain other tuples, objects, and a mix of numbers or strings. Note that tuples in PythonJS are actually JavaScript arrays, so if you modify the contents of the tuple, it would no longer be the same key in a dict.

a = (1,2,3)
b = ("1","2","3")
D = { a: 'hello', b: 'world' }
D[ a ] == 'hello'  ## OK
D[ b ] == 'world'  ## OK
  1. AttributeError and KeyError are only raised in javascript mode when inside a block that catches those errors. In the default python mode these errors will always be thrown, and halt the program.
pythonjs.configure(javascript=True)
a = {}
# this will not throw any error
b = a['xxx']
# this works as expected, "b" will be set to "my-default"
b = a['xxx'] except KeyError: 'my-default'

pythonjs's People

Contributors

amirouche avatar bitdeli-chef avatar bwiklund avatar shekhargulati avatar techtonik avatar texcoffier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pythonjs's Issues

«from stuff import thing»

How this should be handled since it's compiled it should maybe generate a dependency file or concate everything ?

Transitional exception handler in input reader to report file and line

Hi,

I am failing to get my Python module translated. PythonJS gives stack traces and I am unable to quickly determine the input lines that are causing this harm.

Is it possible to add a high level exceptional handler that is rethrows exception if it occurs, but also reports about lines in input file at the time this occurred? I think it will be a valuable property for every input processor.

pythonscript-0.7.3 doesn't work

I have changed setup.py (line 15)
pythonscript=pythonscript.main:command
to
pythonscript=pythonscript.pythonscript:command

and it works.

This project is awesome !, i like it.

AttributeError: 'Slice' object has no attribute 'value'

...
  File "...lib\ast.py", line 241, in visit
    return visitor(node)
  File "...PythonJS\pythonjs\pythonjs.py", line 138, in visit_Subscript
    return '%s[%s]' % (self.visit(node.value), self.visit(node.slice.value))
AttributeError: 'Slice' object has no attribute 'value'

Improve PythonJS

  • add multiple targets to function calls
  • add multiple return values

New Feature Suggestions

PythonJS very promising project.

Couple of feature suggestions after playing around for a while:

  1. Typed parameters support for functions/methods same as Python 3. We can leverage https://github.com/borisyankov/DefinitelyTyped here.
  2. LuaJIT adaptor: I believe the python dialect is the top reason for programmers love besides standard library. Having multiple backends for a python dialect meta compiler will be of great value. Lua has a great backend for systems, games & web, LuaJIT. I believe supporting Lua adaptor besides JS and Dart will make PythonJS a top-tier project.

implement a modern framework

According to this article http://sporto.github.io/blog/2013/04/12/comparison-angular-backbone-can-ember/ a modern framework should contain:

  • Observables : need data descriptor support
  • Routing: Pushing changes to the browser url hash and listening for changes to act accordingly, integrate this in the in Machinima class
  • View bindings: Using observable objects in views, having the views automatically refresh when the observable object change.
  • Two way bindings: Having the view push changes to the observable object automatically, for example a form input.
  • Partial views: Views that include other views.

- Filtered list views: Having views that display objects filtered by a certain criteria.

improve metaclass support

metaclass support is clunky right now, one must repeat in each class which behavior must overriden define the __metaclass__ attribute. Also it doesn't support class metaclasses

class __init__ generated code is strange

if we compile the following code:

class A:
def init (self, _args, *_kwargs):
pass

class B( A ):
def init (self, _args, *_kwargs):
pass

we will get this:

var A, A_attrs, __A_parents;
__A_attrs = {};
__A_parents = create_array();
var __A___init
= function(args, kwargs) {
var signature, arguments;
signature = {"kwargs": {}, "args": create_array("self"), "vararg": "args", "varkwarg": "kwargs"};
arguments = get_arguments(signature, args, kwargs);
var self = arguments['self'];

var args arguments['args']; <----------------- this line seems redundant

args = get_attribute(list, "call")(create_array(args));
var kwargs = arguments["kwargs"];
kwargs = get_attribute(dict, "call")(create_array(kwargs));

}

A_attrs.__init = A___init;
A = create_class("A", A_parents, __A_attrs);
var B, __B_attrs, __B_parents;
__B_attrs = {};
__B_parents = create_array();
__B_parents.push(A);
var __B___init
= function(args, kwargs) {
var signature, arguments;
signature = {"kwargs": {}, "args": create_array("self"), "vararg": "args", "varkwarg": "kwargs"};
arguments = get_arguments(signature, args, kwargs);
var self = arguments['self'];

var args arguments['args']; <----------------- this line seems redundant

args = get_attribute(list, "call")(create_array(args));
var kwargs = arguments["kwargs"];
kwargs = get_attribute(dict, "call")(create_array(kwargs));

}

B_attrs.__init = B___init;
B = create_class("B", __B_parents, __B_attrs);

'get' method for 'dict' in Javascript mode

When translated in 'javascript' mode, 'dict' is translated as a Javascript 'Object'.

Is it possible to add some builtins methods to the Javascript 'Object' in order to better emulate a Python 'dict'?

I use for example:

    @Object.prototype.get
    def func(key, default_value=None):
        if key in this:
            return this[key]
        return default_value

Improve tests and implement test suite

Create more tests and implement a run_tests function for complete check:

  • check pythonjs output in python
  • check pythonjs output is working as expected execute with node
  • check pythonscript output in python
  • check pythonscript output is working as expected execute with node

test_if_true

getattr is broken by a bug in test_if_true, there is the patch :

--- a/runtime/builtins.py
+++ b/runtime/builtins.py
@@ -39,6 +39,8 @@ with javascript:
                        return True

        def __test_if_true__( ob ):
+               if JS("! ob"):
+                       return False
                if instanceof(ob, Array):
                        return ob.length != 0
                elif isinstance(ob, dict):

You may add a regression test regtests/class/attr.py:

"""instance attributes"""

class A:
    g = 6
    def __init__(self):
        self.b = 5

def main():
    a = A()

    TestError(a.b == 5)
    TestWarning(a.g == 6)
    try:
        x = a.c
        TestWarning(not 'No exception: on undefined attribute')
    except AttributeError:
        pass

    TestError(getattr(a, 'b') == 5)
    TestWarning(getattr(a, 'g') == 6)
    # TestWarning(getattr(a, 'c', 42) == 42)
    try:
        getattr(a, 'c')
        TestWarning(not 'No exception: getattr on undefined attribute')
    except AttributeError:
        pass

I did not submit a tree because I can no more recreate the same pythonjs.js file than original one, there is tons of:

-  __sig__ = {"kwargs": {"property": false}, "args": __create_array__("ob", "attr", "property")};
+  __sig__ = { kwargs:{"property": false},args:__create_array__("ob", "attr", "property") };

'in' python operator translations

The following Python code

with javascript:
     print 'o' in 'kok'

Is translated as:

console.log(Object.hasOwnProperty.call("kok", "__contains__")
            && "kok"["__contains__"]("o")
            || Object.hasOwnProperty.call("kok", "o"));

The previous code does not work, but this trivial code works as expected:

console.log("kok".__contains__('o'))

Benchmarks?

This looks great! I actually have abandoned my tornado code for Node.js/Express. Are there any benchmarks? How does this stack up against the real Tornado?

PyPI version (0.8.3) is outdated

Trying to compile the simple code 10**2 gives a SyntaxError with PythonJS 0.8.3 (installed with pip), but I noticed it works with the latest version on GitHub.

Might be a good idea to update the version on PyPi.

fully implement exceptions

right now there is not filtering that is possible only the following syntax is supported

try:
     raise SomethingIfYouWant
except:
    if __exception__ == SomethingIfYouWant:
        print 'ouhou'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.