transcryptorg / transcrypt Goto Github PK
View Code? Open in Web Editor NEWPython 3.9 to JavaScript compiler - Lean, fast, open!
Home Page: https://www.transcrypt.org
License: Apache License 2.0
Python 3.9 to JavaScript compiler - Lean, fast, open!
Home Page: https://www.transcrypt.org
License: Apache License 2.0
similar to https://github.com/JdeH/Transcrypt/issues/24
Python
default = True
if default:
print("defaulting")
Generates Javascript
var default = true;
if (default) {
print ('defaulting');
}
SyntaxError: missing variable name
Maybe I'm just really dumb, but it took me longer than I'd like to admit to figure out where the generated .js output is placed. :)
I tried to run a simple test script like the docs say and the only output is "Ready":
$ transcrypt -b test.py
Transcrypt (TM) Python to JavaScript Small Sane Subset Transpiler Version 3.5.132
Copyright (C) Geatec Engineering. License: Apache 2.0
Ready
I wasn't sure if that meant something was generated or if it maybe meant that it didn't generate anything because I used the wrong command. I looked in the current folder for a new test.js
file, but I didn't find anything. So I tried various command line options but just got the same cryptic message.
Thinking I must be missing something obvious, I searched through the docs, but I couldn't find (either on the website or the project README) any actual examples of running the transcript tool on the command line.
It wasn't until I tried transcrypt -bv
that I actually saw all the output was created in a /__javascript__
sub-folder! This was frustrating because I just wanted to try out your great app and couldn't find the output :)
Would you consider adding "Saving result in: /javascript/test.js" as part of the non-verbose default command output? Or if not that, maybe making it more clear in the docs where the output is placed?
I apologize if this is already mentioned somewhere in the docs, but I didn't see it when skimming through the various pages and forum posts. I know this sounds like a dumb user problem, but I'm guessing other new users will run into the same confusion.
Thanks!
Hi,
First let me apologize for using the github issue system for what is not really a bug report. I am simply too lazy to sign into another forum :)
I just wanted to let you know that the of the major features you quote for Transcrypt: "Multiple inheritance, recursive tuple assignment, multi-loop nested list comprehensions, LHS and RHS extended slices, assignment of bound functions, lambdas, named, default, _args and *_kwargs parameters, properties and a hierarchical module system are just a few of its characteristics that make this clear."
only multiple inheritance is not currently supported by RapydScript. Specifically, by the work I have been doing on rapydscript https://github.com/kovidgoyal/rapydscript-ng
And adding support for multiple inheritance should not take more than a day or two of work -- it just isn't a priority for me.
RapydScript has many features it would take a fair bit of effort to duplicate: a REPL, support for gettext, a linter, a minifier, set,dict,generator comprehensions, yield and generators, ESS5 and ES6 profiles, and so on.
This is only an FYI -- it would be nice to be able to combine efforts on a single python-like transpiler, but, I totally understand if you would rather go it on your own.
The index() function should be indexOf() in the translated javascript?
I was trying out the examples from the python tutorial at https://docs.python.org/3/tutorial/ , but almost none of the dictionary examples work. Below is the code I am using. Am I doing something wrong? Is more support planned in the future?
Almost all the other tutorial code I have tried has worked great so far. Very exciting project, thank you!
def test():
#examples from
#https://docs.python.org/3/tutorial/datastructures.html#dictionaries
tel = {'jack': 4098, 'sape': 4139}
tel['guido'] = 4127
print (tel) #{'sape': 4139, 'guido': 4127, 'jack': 4098}
print (tel['jack']) #4098
del tel['sape']
tel['irv'] = 4127
print (tel) #{'guido': 4127, 'irv': 4127, 'jack': 4098}
#ERROR Uncaught TypeError: tel.keys is not a function:
print ( list(tel.keys()) ) #['irv', 'guido', 'jack']
print ( sorted(tel.keys()) ) #['guido', 'irv', 'jack']
#ERROR Uncaught TypeError: container.indexOf is not a function:
print ('guido' in tel) #True
print ('jack' not in tel) #False
#ERROR Uncaught ReferenceError: pair is not defined:
print ( dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])) #{'sape': 4139, 'jack': 4098, 'guido': 4127}
knights = {'gallahad': 'the pure', 'robin': 'the brave'}
#ERROR Uncaught TypeError: knights.items is not a function:
for k, v in knights.items():
print (k, v)
#gallahad the pure, robin the brave
if 'gallahad' in knights:
print ('gallahad is a knight') #gallahad is a knight
for k in knights:
print (k) #gallahad, robin
test()
Python
class Foo:
def __init__(self, a, b=99):
self.a = a
self.b = b
f = Foo(1, b=2)
print("f.a", f.a)
print("f.b", f.b)
f.a 1
f.b 2
Generated Javascript
var Foo = __class__ ('Foo', [object], {
get __init__ () {return __get__ (this, function (self, a, b) {
if (typeof b == 'undefined' || (b != null && b .__class__ == __kwargdict__)) {;
var b = 99;
};
self.a = a;
self.b = b;
});}
});
var f = Foo (1, __kwargdict__ ({b: 2}));
print ('f.a', f.a);
print ('f.b', f.b);
f.a 1
f.b 99
When foo is called below, bar is self and baz is 1. The self argument should not have been passed.
class SomeClass:
@staticmethod
def foo(bar, baz):
return str(bar+baz)
fooed = self.foo(1, 2)
foo = ['bar', 'baz']
del foo[0]
#foo.pop(0) # workaround
print("foo len", len(foo), foo)
prints: "foo len 2 ,baz"
One thing I like about Python, is that it has namespaces and variables don't just come out of nowhere.
Here is example:
__pragma__('alias', 'jQuery', '$')
def start():
def changeColors(divs):
for div in divs:
rgb = [int(256 * Math.random()) for i in range(3)]
jQuery(div).css({'color': 'rgb({},{},{})'.format(*rgb)})
changeColors(jQuery('div'))
window.setInterval(changeColors, 500)
This code has 4 undefined variables, that comes out of nowhere. All Python static syntax checkers will issue number of errors, for example:
> pyflakes jquery.py
jquery.py:1: undefined name '__pragma__'
jquery.py:6: undefined name 'Math'
jquery.py:7: undefined name 'jQuery'
jquery.py:9: undefined name 'jQuery'
jquery.py:10: undefined name 'window'
Having a namespace that represents JavaScript global namespace would solve this issue, for example:
import __transcrypt__
import __javascript__ as js
__transcrypt__.alias('jQuery', '$')
def start():
def changeColors(divs):
for div in divs:
rgb = [int(256 * js.Math.random()) for i in range(3)]
js.jQuery(div).css({'color': 'rgb({},{},{})'.format(*rgb)})
changeColors(js.jQuery('div'))
js.window.setInterval(changeColors, 500)
Now, there is no undefined variables and it is clear what comes from JavaScript or Transcrypt and what is defined in Python modules.
Python
foo = []
print("not foo", not foo)
results in
not foo True
Generated Javascript
var foo = list ([]);
print ('not foo', !foo);
results in
not foo false
Hi,
I couldn't get transcrypt to work on an Ubuntu15 machine. Here's what I did:
I added the directory to the path
I cd'ed to the path Transcyrpt/development/automated_tests/transcrypt
I ran 'transcrypt' which gives me
Transcrypt (TM) Python to JavaScript Small Sane Subset Transpiler Version 3.5.70
Copyright (C) Geatec Engineering. License: Apache 2.0
Usage: transcrypt.py [-h] [-k] [-b] [-l] [-r] [-v] [source
So from that I figured that the installation is ok.
I ran 'transcrypt -b autotest.py' which gave me
Transcrypt (TM) Python to JavaScript Small Sane Subset Transpiler Version 3.5.70
Copyright (C) Geatec Engineering. License: Apache 2.0
[Errno 2] No such file or directory: 'java'Ready
What am I doing wrong?
Thanks,
Dirk
Similar to https://github.com/JdeH/Transcrypt/issues/40
Python
print("(240+30-1) // 30 * 30 =", (240+30-1) // 30 * 30)
(240+30-1) // 30 * 30 = 240
Generated Javascript via Version 3.5.160
print ('(240+30-1) // 30 * 30 =', (Math.floor ((240 + 30) - 1 / 30)) * 30);
(240+30-1) // 30 * 30 = 8070
Python min() and max() should translate to Math.min() and Math.max() in generated javascript.
First of all, thanks for all the work on this project!
I tried out Transcript and the end of each generated .js file looks like this:
window ['test'] = test ();
This fails on Node.js because there is no window
object when running javascript on the server:
$ node __javascript__/test.js
/Users/ageitgey/Desktop/__javascript__/test.js:977
window ['test'] = test ();
^
ReferenceError: window is not defined
To make the generated code work on Node.js, all you have to do is remove is this:
// Original code
window ['test'] = test ();
// Change to:
test ();
I know your main use case might be to generate .js to run in the browser. But would it be possible to support generating code that doesn't assume there is a window
object? Maybe it could be done via an optional parameter if you prefer the current behavior?
You seem to have a unique Python coding style. Specifically, the space character before brackets is uncommon in Python, but I've seen that in some JavaScript code before.
I suggest you run flake8 over your whole code base. I also suggest you run flake8
and all your tests on a CI server (e.g. Travis) on every single push and PR on the repository.
In python and brython i could do this:
class OnlyOne(object):
class __OnlyOne:
def __init__(self):
self.val = None
instance = None
def __new__(cls):
if not OnlyOne.instance:
OnlyOne.instance = OnlyOne.__OnlyOne()
return OnlyOne.instance
def __getattr__(self, name):
return getattr(self.instance, name)
def __setattr__(self, name):
return setattr(self.instance, name)
x = OnlyOne()
x.val = 'sausage'
console.log(x.val)
y = OnlyOne()
y.val = 'eggs'
console.log(y.val)
z = OnlyOne()
z.val = 'spam'
console.log(z.val)
console.log(x.val)
console.log(y.val)
but resulting an error in transcrypt:
TypeError: OnlyOne.__OnlyOne is not a function
Chrome's debugger supports the use of source maps, which produce a mapping from the minified code that is being executed to the source files that produced it. When source maps are used, you can step through the original code and even set breakpoints, while Chrome internally executes the minifiied code.
Javascript transpilers such as Babel, TypeScript and coffeescript all support generating source maps to allow the developer to see the source files in Chrome and not the generated JS. Recent builds of Chrome have source maps enabled by default.
It would be a killer feature to have source maps for Transcrypt generated code, so that you can work with Python in the Chrome debugger.
after "pip3 install transcrypt" on ubuntu 15.10 i get
ImportError: No module named 'org'
while trying >>> import Transcrypt.transcript
Python
a = ['1', '2', '3']
print(a)
print(''.join(a))
b = [1, 2, 3]
print(b)
print(''.join(str(bb) for bb in b))
['1', '2', '3']
123
[1, 2, 3]
123
Generated Javascript
var a = list (['1', '2', '3']);
print (a);
print (''.join (a));
var b = list ([1, 2, 3]);
print (b);
print (''.join (str (bb)bbb));
SyntaxError: missing ) after argument list
Currently the only way of creating a js
is calling the cli
interface. Even calling the underlying code is not working as it relays on global defined variables for cli
. Also the compiler
is only importable over a hack.
import tempfile
import sys
import os
def transcrypt_code(code):
"""
The api is pretty messy so to get it working we create a tem file
"""
import transcrypt
transpilerDir = transcrypt.__path__._path[0]
modulesDir = '{}/modules'.format(transpilerDir)
# Both CPython and Transcrypt will use all dirs in sys.path as search roots for modules
# CPython will also search relatively from each module, Transcrypt only
# from the main module
sys.path = [modulesDir] + sys.path
sys.modules.pop('org', None)
from org.transcrypt import compiler
name = None
with tempfile.NamedTemporaryFile() as f:
name = f.name
f.write(code.encode())
compiler.Program(name)
with open(os.path.join(
os.path.dirname(name), "__javascript__",
os.path.basename(name) + ".js")) as f:
ret = f.read()
return ret
if __name__ == "__main__":
transcrypt_code("print('helo')")
This results in an error:
Traceback (most recent call last):
File "trans.py", line 39, in <module>
transcrypt_code("print('helo')")
File "trans.py", line 30, in transcrypt_code
compiler.Program(name)
File "/tmp/env3/lib/python3.5/site-packages/transcrypt/modules/org/transcrypt/compiler.py", line 93, in __init__
self.rawModuleCaption = '\n\n// ============ Source: {} ============\n\n' if utils.commandArgs.anno else ''
AttributeError: 'CommandArgs' object has no attribute 'anno'
Python
assert False, "some error here"
generates
Javascript
false'some error here';
There needs to be an assert() function generated similar to how print() works.
There seems to be some confusion in the codebase. It advertises itself up-front as Apache (i.e. via the license stub emitted form the command-line interface, the file included in the package, etc.) but also on some source files lists a private license.
Is this code mixed-license?
does transcrypt have an alternative to javascripts new keyword? this is important in constructing javascript objects from python code. I have solved this for now by defining a javascript function new_:
function new_(code)
{
return eval("new "+code)
}
which can then be used like so:
preload_queue=new_("createjs.LoadQueue();")
but this isn't a great solution, every object instanciation from python code would incur parsing costs. a much cleaner solution would be to have a magic new() function that transcrypt translates to the new keyword.
am I missing something or is this indeed a missing feature?
Hi, @datnamer pointed this project out to me (flexxui/flexx#54), nice project! It seems to have a lot of common with what I am trying to do with flexx.pyscript
. At least, of all the python-to-js solutions, this is by far the most similar I've seen :)
On the thread on reddit you mentioned that you've checked Flexx out but that it did not have what you needed. As far as I can tell the biggest difference is that Flexx does currently support multiple inheritance or bound functions. I'd be happy to have this changed though. I also want to stress that although the Flexx project itself is about providing a full widget toolkit, flexx.pyscript
is self-contained. E.g. we're using it in Bokeh as well.
I was wondering about how you do the ast parsing. I'm using the buildin ast module myself, and have written a sort of compatibility layer (commonast.py) to make it work across different Python versions (support for Python 2.7 to be added like this week). If anything, this would be one place where our projects could potentially share code.
Another question is how you (plan to) handle things like "a string" * 3
. Is that going to produce "a string3"
as in JS or "a stringa stringa string"
as in Python? I chose the latter, but I needed some operator overloading to make that work.
Due to a regression, from ... import ... will initialize a module multiple times.
Will be fixed in next version...
How would you go about using Underscore style inheritance? I'm thinking specifically about writing a Backbone app in Python code, which means I need to create a bunch of Python classes that "extend" these Javascript "fake" classes such as Model
, Controller
, etc.
There are some files and folders which are not supposed to be under version control, e.g.
*.egg-info
(they can be regenerated anytime)*.pyc
) and Python3's __pycache__
folder (generated by Python, may produce unpleasant side-effects when distributed to other systems)transcrypt.npp
(is highly dependent on your local system, and changes frequently)I suggest you remove them from the repository, and add a .gitignore
file with appropriate definitions to avoid adding any such files by mistake in future. See GitHub's gitignore repository for useful samples.
Python
def foo():
class Bar:
def __init__(self, name):
self.name = name
b = Bar('foo')
print("b.name =", b.name)
foo()
Generated Javascript
var foo = function () {
var Bar = __class__ ('Bar', [object], {
get __init__ () {return __get__ (this, function (self, name) {
self.name = name;
});}
});
var b = Bar ('foo');
print ('b.name =', b.name);
};
Causes
TypeError: "name" is read-only
I've not looked at the fix, but this seems similar to https://github.com/JdeH/Transcrypt/issues/24
Python
c1 = 2
c2 = 1
c3 = 2
foo = c1 / (c2 * c3)
print('foo = ', foo)
c4 = c2 * c3
bar = c1 / c4
print('bar = ', bar)
foo = 1.0
bar = 1.0
Generated Javascript
var c1 = 2;
var c2 = 1;
var c3 = 2;
var foo = c1 / c2 * c3;
print ('foo = ', foo);
var c4 = c2 * c3;
var bar = c1 / c4;
print ('bar = ', bar);
foo = 4
bar = 1
The following code generates
SyntaxError: super() is only valid in derived class constructors
class foo:
def bar(self):
print('bar')
class foo2(foo):
def bar(self):
print('bar2')
super().bar()
# foo.bar(self) # workaround
The error message seems to imply it works in derived constructors, but using it there generates the same error.
I would like to use React.js with a flask app, but I don't want to learn JS.
Would this let me use react.js and code in python syntax in a maintainable un hackish way?
Its not your average JS framework because it has a DSL type thing going with virtual dom and reactive dataflow programming.
Generated code contains the following code which generates
TypeError: can't redefine non-configurable property "format"
Object.defineProperty (String.prototype, 'format', { get: function () {return __get__ (this, function (self) { var args = tuple ([] .slice.apply (arguments).slice (1)); var autoIndex = 0; return self.replace (/\{(\w*)\}/g, function (match, key) { if (key == '') { key = autoIndex++; } if (key == +key) { return args [key] == 'undefined' ? match : args [key]; } else { for (var index = 0; index < args.length; index++) { if (typeof args [index] == 'object' && typeof args [index][key] != 'undefined') { return args [index][key]; } } return match; } }); });}, enumerable: true });
Python
def reversed_index(items, value):
for pos, curr in enumerate(reversed(items)):
if curr == value:
return len(items) - pos - 1
return -1
The generated code has parameter items referred to as py_items in the function body.
var reversed_index = function (items, value) {
var __iter0__ = enumerate (reversed (py_items));
for (var __index0__ = 0; __index0__ < __iter0__.length; __index0__++) {
var __left0__ = __iter0__ [__index0__];
var pos = __left0__ [0];
var curr = __left0__ [1];
if (curr == value) {
return len (py_items) - pos - 1;
}
}
return -1;
};
For some reason currently the sourcefiles that the maps refer to are not copied on Linux.
I'll switch it off...
Python
foo4 = 'foo4'
four = foo4[3:]
```Generates
Javascript
var foo4 = 'foo4';
var four = foo4.getslice (3, null, 1);
Causes
TypeError: foo4.__getslice__ is not a function
In javascript switch is a keyword, so the following
Python
switch = False
if switch:
print("switching")
Generates the invalid
Javascript
var switch = false;
if (switch) {
print ('switching');
}
A big part of the benefit of a Python to JavaScript transpiler is the ability to use libraries from the Python ecosystem. Obviously, we won't be able to use libraries that do I/O or depend on C modules, but things like https://pypi.python.org/pypi/deferred or https://pypi.python.org/pypi/attrs or https://pypi.python.org/pypi/six or https://pypi.python.org/pypi/Automat are important to be able to use code consistently between clients and servers. Looking through the documentation, I don't see any way to go from a Python virtualenv
with all these things installed to a redistributable bundle.
I don't know Transcrypt well enough to know if this is a feature request or just a documentation request, but I would like to do it.
Python
def is_one(val):
return val==1
foo = [1, 2, 3]
print("any foo", any(is_one(v) for v in foo))
bar = [11, 2, 3]
print("any bar", any(is_one(v) for v in bar))
any foo True
any bar False
Converted Javascript
var is_one = function (val) {
return val == 1;
};
var foo = list ([1, 2, 3]);
print ('any foo', any (is_one (v)vfoo));
var bar = list ([11, 2, 3]);
print ('any bar', any (is_one (v)vbar));
gets SyntaxError: missing ) after argument list
Python
print("15 // 7 = ", 15 // 7)
15 // 7 = 2
Generated Javascript
print ('15 // 7 = ', Math.floor (15) / Math.floor (7));
15 // 7 = 2.142857142857143
Python
print('{1,2} == {2,1} =', {1,2} == {2,1})
{1,2} == {2,1} = True
Generated Javascript
print ('{1,2} == {2,1} =', new set ([1, 2]) == new set ([2, 1]));
{1,2} == {2,1} = false
Python
foo = [1, 2, 3]
print("foo last", foo[-1])
foo last 3
Generated Javascript
var foo = list ([1, 2, 3]);
print ('foo last', foo [-1]);
foo last undefined
Could not make it work:
> python --version
Python 3.5.1
> transcrypt -b testme.py
Transcrypt (TM) Python to JavaScript Small Sane Subset Transpiler Version 3.5.113
Copyright (C) Geatec Engineering. License: Apache 2.0
module 'site' has no attribute 'getsitepackages'Ready
> cat testme.py
for i in range(10):
console.log(i)
Hi,
Looks like keyword arguments are badly implemented
class Level(object):
def __init__(self, a, b):
print('a:')
print(a)
print('b:')
print(b)
l = Level(1, 2)
m = Level(a=1, b=2)
This code will give the following:
a:1
b:2
a:[object Object]
b:undefined
where second a
is {a: 1, b: 2}
Python code
foo = ['a', 'b', 'c']
for i in range(len(foo)):
print("popped", foo.pop(0))
Prints
popped a
popped b
popped c
Generated Javascript
var foo = list (['a', 'b', 'c']);
for (var i = 0; i < len (foo); i++) {
print ('popped', foo.py_pop (0));
}
Prints
popped a
popped b
The length of foo needs to be captured before the loop runs..something like
for (var i = 0, j=len (foo); i < j; i++) {
Python
foo = 'foocba'
print(foo.strip('abc'))
foo
Generated javascript prints
foocba
Transcrypt has a bug in the way it compiles code for default values of arguments to lambda functions. The bug is serious, because the ability to close on several different values in callback functions for ajax calls is crucial for ajax programming.
Python closures capture variables, not their values. The hack in Python to create a closure that captures the value of a variable rather than the variable itself is like this:
for r in rows.indexes():
row = rows.row(r)
deferreds.append(JQ.post("assign_to_run", {'run': run, 'sample_data': JSON.stringify([row.data()[12]])}) \
.done(lambda *, rw=row: rw.deselect() ))
but Transcrypt does not capture the value of row
into rw
. Instead it treats it as a closure over the variable row
itself:
for (var __index0__ = 0; __index0__ < __iter0__.length; __index0__++) {
var r = __iter0__ [__index0__];
var row = rows.row (r);
deferreds.append ($.post ('assign_to_run', dict ({'run': run, 'sample_data': JSON.stringify (list ([row.data () [12]]))})).done ((function __lambda__ () {
var rw = row;
return rw.deselect ();})));
}
When the above javascript code is run it will call deselect()
on the last value assigned to row
as many times as there were loop iterations, which isn't what it should be doing.
Python
a = [1, 2, 3]
a.append(4)
print(a)
a += [5, 6, 7]
print(a)
[1, 2, 3, 4]
[1, 2, 3, 4, 5, 6, 7]
Generated Javascript
var a = list ([1, 2, 3]);
a.append (4);
print (a);
a += list ([5, 6, 7]);
print (a);
[1, 2, 3, 4]
1,2,3,45,6,7
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.