Brython - Python in the browser

P

Pierre Quentel

Hi,

The objective of Brython is to replace Javascript by Python as the scripting language for web browsers, making it usable on all terminals including smartphones, tablets, connected TVs, etc. Please forgive the lack of ambition;-)

The best introduction is to visit the Brython site (http://www.brython.info). Right click on the page with a clock and take a look at the source code : no Javascript, only Python code inside a tag <script type="text/python">. You will notice the inclusion of a script brython.js in the HEAD section, and a call to the function brython() when the page is loaded : that's allit takes

Brython is both a Python to Javascript translator, and a Python interface to the Document Object Model. For instance, access to a DOM element by its id is done by

doc[element_id]

where "doc" is a keyword referencing the document. To create an element, for instance an HTML anchor :

doc <= A('Python',href="http://www.python.org")

The element is created by a built-in class called A, like the HTML tag ; itis inserted in the document by the operator <= which is obviously not "lesser or equal", but an arrow meaning "add child"

Brython is at a very early stage, but already usable : you can visit the gallery with a few applications using Ajax calls, HTML5 local storage, drag and drop, canvas etc. The performance is below pure Javascript, but not by far : the 3D demo is almost as fluid as its Javascript equivalent

It still lacks important features of Python, mostly list comprehensions andclasses ; the documentation is limited, there are bugs, the testing process is rudimentary, performance can still improve. For all its current limitations, since I first announced it to a limited audience, the reactions havebeen very positive (see for instance this blog entry by François Dion : http://raspberry-python.blogspot.fr/2012/12/brython-browser-python.html)

If you are interested in this project, there are many ways to contribute :
- report bugs or suggest new features on the issue tracker (http://code.google.com/p/brython/issues/list) : there is a console at http://brython.info/tests/console_en.html to test online, or you can download a local distribution from the development site
- write code : the priority is to extend the built-in Javascript modules (time.js, math.js, etc) - I'm ready to support developers willing to work on this
- contribute to the documentation, translate into other languages, write a tutorial, etc
- promote Brython in forums, blogs, tweets, events, etc
- if you develop demos or apps with Brython, send a link to the community (https://groups.google.com/forum/?fromgroups=#!forum/brython), it will be added to the gallery on brython.info

Enjoy !
Pierre
 
J

jkn

Hi Pierre
this looks very interesting, thanks. But I wonder ... do you know of pyjs (pyjamas as-was)? http://pyjs.org/

I would be interested in a comparison between (the aims of) Brython and pyjs.

Either way, thanks for the info.

Regards
Jon N
 
T

Terry Reedy

The objective of Brython is to replace Javascript by Python as the
scripting language for web browsers, making it usable on all
terminals including smartphones, tablets, connected TVs, etc. Please
forgive the lack of ambition ;-)

This sounds similar to pyjs, but the latter has two big problems: a)
personality conflicts splits among the developers; b) last I knew, it
was stuck on Python 2.

I think your home page/doc/announcement should specify Python 3 at the
top, so it is not a mystery until one reads down to
"Brython supports most keywords and functions of Python 3 : "

"lists are created with [] or list(), tuples with () or tuple(),
dictionaries with {} or dict() and sets with set()"

non-empty sets are also created with {} and you should support that.
The best introduction is to visit the Brython site
(http://www.brython.info).

That says that my browser, Firefox 17, does not support HTML5. Golly
gee. I don't think any browser support5 all of that moving target, and
Gecko apparently supports about as large a subset as most.
https://en.wikipedia.org/wiki/Comparison_of_layout_engines_(HTML5)
It is possible the FF still does not support the particular feature
needed for the clock, but then the page should say just that. Has the
latest FF (17) actually been tested?
To create an element, for instance an HTML anchor :
doc <= A('Python',href="http://www.python.org")

To me, that is a awful choice and I urge you to change it.

'<=' is not just an operator, it is a comparison operator. It normally
return False or True. Numpy array comparison returns arrays of booleans,
so the meaning is extended, not completely changed. People will often be
using it with its normal mean in conditionals elsewhere, so this usage
creates strong cognitive dissonance. Also, using an expression as a
statement is allowed, but except in the interactive interpreter, it only
makes sense with an expression that obviously has side-effects or could
have side-effects (like the expression 'mylist.sort()'. It just looks
wrong to an experienced Python programmer like me.

It also is unnecessary. Use '+=' or '|='. The former means just what you
want the statement to do and the latter is at least somewhat related
(bit or-addition) and is rarely used and is very unlikely to be used in
code intended for a browser.

It still lacks important features of Python, mostly list
comprehensions and classes ;

Since Python 3 has 4 types of comprehensions, while Python 2 only has
list comprehensions, I took this to mean that Brython was Python 2.

And yes, I am all in favor of being able to use a subset of Py3 instead
of javascript. A full Python interpreter in a browser is too dangerous.
(Actually, I think javascript is too, but that is a different issue.)
Python translated to javascript cannot be worse than javascript. I
presume the same would be true if the javascript step were omitted and
Python were directly compiled to the virtual machines defined by current
javascript engines.
 
I

Ian Kelly

That says that my browser, Firefox 17, does not support HTML5. Golly gee. I
don't think any browser support5 all of that moving target, and Gecko
apparently supports about as large a subset as most.
https://en.wikipedia.org/wiki/Comparison_of_layout_engines_(HTML5)
It is possible the FF still does not support the particular feature needed
for the clock, but then the page should say just that. Has the latest FF
(17) actually been tested?

It works for me using FF 17.0.1.
To me, that is a awful choice and I urge you to change it.

+1. The DOM already has a well-established API. The following may
require more typing:

link = document.createElement('a')
link.setAttribute("href", "http://www.python.org/")
link.appendChild(document.createTextNode('Python'))
document.body.appendChild(link)

But it is much clearer in intent. Since these methods map directly to
DOM methods, I know exactly what I expect them to do, and I can look
them up in the browser documentation if I have any doubts. With the
one-liner above, I don't know exactly what that maps to in actual DOM
calls, and so I'm a lot less clear on what exactly it is supposed to
do. I'm not even entirely certain whether it's actually equivalent to
my code above.

I suggest that Brython should have a "low-level" DOM API that matches
up to the actual DOM in as close to a 1:1 correspondence as possible.
Then if you want to have a higher-level API that allows whiz-bang
one-liners like the above, build it as an abstraction on top of the
low-level API and include it as an optional library. This has the
added benefit that if the user runs into an obscure bug where the
fancy API breaks on some particular operation on some specific
browser, they will still have the option of falling back to the
low-level API to work around it. It would also make the conversion
barrier much lower for web programmers looking to switch to Brython,
if they can continue to use the constructs that they're already
familiar with but just write them in Python instead of JavaScript.
 
T

Terry Reedy

It works for me using FF 17.0.1.

It works for me too when ignore the mistaken and misleading error
message and just turn on javascript for the page. Some sites say things
like "You have javascript turned off. Turn it on to see all features."
+1. The DOM already has a well-established API. The following may
require more typing:

link = document.createElement('a')
link.setAttribute("href", "http://www.python.org/")
link.appendChild(document.createTextNode('Python'))
document.body.appendChild(link)

But it is much clearer in intent.

I agree with the rest of your suggestion.
 
P

Pierre Quentel

Le jeudi 20 décembre 2012 01:07:15 UTC+1, Terry Reedy a écrit :
This sounds similar to pyjs, but the latter has two big problems: a)

personality conflicts splits among the developers; b) last I knew, it

was stuck on Python 2.
It is indeed different from pyjs : both translate Python into Javascript, but with Brython the translation is done on the fly by the browser, with pyjs is is done once by a Python script
I think your home page/doc/announcement should specify Python 3 at the

top, so it is not a mystery until one reads down to

"Brython supports most keywords and functions of Python 3 : "
Done on the home page


"lists are created with [] or list(), tuples with () or tuple(),

dictionaries with {} or dict() and sets with set()"



non-empty sets are also created with {} and you should support that.
Ok, I put this point in the issue tracker
That says that my browser, Firefox 17, does not support HTML5. Golly

gee. I don't think any browser support5 all of that moving target, and

Gecko apparently supports about as large a subset as most.

https://en.wikipedia.org/wiki/Comparison_of_layout_engines_(HTML5)

It is possible the FF still does not support the particular feature

needed for the clock, but then the page should say just that. Has the

latest FF (17) actually been tested?
I changed the error message adding "or Javascript is turned off"
To me, that is a awful choice and I urge you to change it.



'<=' is not just an operator, it is a comparison operator. It normally

return False or True. Numpy array comparison returns arrays of booleans,

so the meaning is extended, not completely changed. People will often be

using it with its normal mean in conditionals elsewhere, so this usage

creates strong cognitive dissonance. Also, using an expression as a

statement is allowed, but except in the interactive interpreter, it only

makes sense with an expression that obviously has side-effects or could

have side-effects (like the expression 'mylist.sort()'. It just looks

wrong to an experienced Python programmer like me.



It also is unnecessary. Use '+=' or '|='. The former means just what you

want the statement to do and the latter is at least somewhat related

(bit or-addition) and is rarely used and is very unlikely to be used in

code intended for a browser.
I'm afraid I am going to disagree. The document is a tree structure, and today Python doesn't have a syntax for easily manipulating trees. To add a child to a node, using an operator instead of a function call saves a lot of typing ; <= looks like a left arrow, which is a visual indication of the meaning "receive as child". |= doesn't have this arrow shape

+= is supported by Brython, but it means something different. <= means "add child" ; the addition operator + means "add brother"

For instance,

d = UL(LI('test1'))
d += UL(LI('test2'))
doc <= d

will show two unordered lists at the same level, while

d = UL(LI('test1'))
d <= UL(LI('test2'))
doc <= d

will nest the second list inside the first one

In fact, even in CPython there could be a built-in tree class that could bemanaged by a syntax such as this one
 
P

Pierre Quentel

Le jeudi 20 décembre 2012 01:07:15 UTC+1, Terry Reedy a écrit :
This sounds similar to pyjs, but the latter has two big problems: a)

personality conflicts splits among the developers; b) last I knew, it

was stuck on Python 2.
It is indeed different from pyjs : both translate Python into Javascript, but with Brython the translation is done on the fly by the browser, with pyjs is is done once by a Python script
I think your home page/doc/announcement should specify Python 3 at the

top, so it is not a mystery until one reads down to

"Brython supports most keywords and functions of Python 3 : "
Done on the home page


"lists are created with [] or list(), tuples with () or tuple(),

dictionaries with {} or dict() and sets with set()"



non-empty sets are also created with {} and you should support that.
Ok, I put this point in the issue tracker
That says that my browser, Firefox 17, does not support HTML5. Golly

gee. I don't think any browser support5 all of that moving target, and

Gecko apparently supports about as large a subset as most.

https://en.wikipedia.org/wiki/Comparison_of_layout_engines_(HTML5)

It is possible the FF still does not support the particular feature

needed for the clock, but then the page should say just that. Has the

latest FF (17) actually been tested?
I changed the error message adding "or Javascript is turned off"
To me, that is a awful choice and I urge you to change it.



'<=' is not just an operator, it is a comparison operator. It normally

return False or True. Numpy array comparison returns arrays of booleans,

so the meaning is extended, not completely changed. People will often be

using it with its normal mean in conditionals elsewhere, so this usage

creates strong cognitive dissonance. Also, using an expression as a

statement is allowed, but except in the interactive interpreter, it only

makes sense with an expression that obviously has side-effects or could

have side-effects (like the expression 'mylist.sort()'. It just looks

wrong to an experienced Python programmer like me.



It also is unnecessary. Use '+=' or '|='. The former means just what you

want the statement to do and the latter is at least somewhat related

(bit or-addition) and is rarely used and is very unlikely to be used in

code intended for a browser.
I'm afraid I am going to disagree. The document is a tree structure, and today Python doesn't have a syntax for easily manipulating trees. To add a child to a node, using an operator instead of a function call saves a lot of typing ; <= looks like a left arrow, which is a visual indication of the meaning "receive as child". |= doesn't have this arrow shape

+= is supported by Brython, but it means something different. <= means "add child" ; the addition operator + means "add brother"

For instance,

d = UL(LI('test1'))
d += UL(LI('test2'))
doc <= d

will show two unordered lists at the same level, while

d = UL(LI('test1'))
d <= UL(LI('test2'))
doc <= d

will nest the second list inside the first one

In fact, even in CPython there could be a built-in tree class that could bemanaged by a syntax such as this one
 
P

Pierre Quentel

Le jeudi 20 décembre 2012 01:54:44 UTC+1, Ian a écrit :
It works for me using FF 17.0.1.






+1. The DOM already has a well-established API. The following may

require more typing:



link = document.createElement('a')

link.setAttribute("href", "http://www.python.org/")

link.appendChild(document.createTextNode('Python'))

document.body.appendChild(link)



But it is much clearer in intent. Since these methods map directly to

DOM methods, I know exactly what I expect them to do, and I can look

them up in the browser documentation if I have any doubts. With the

one-liner above, I don't know exactly what that maps to in actual DOM

calls, and so I'm a lot less clear on what exactly it is supposed to

do. I'm not even entirely certain whether it's actually equivalent to

my code above.



I suggest that Brython should have a "low-level" DOM API that matches

up to the actual DOM in as close to a 1:1 correspondence as possible.

Then if you want to have a higher-level API that allows whiz-bang

one-liners like the above, build it as an abstraction on top of the

low-level API and include it as an optional library. This has the

added benefit that if the user runs into an obscure bug where the

fancy API breaks on some particular operation on some specific

browser, they will still have the option of falling back to the

low-level API to work around it. It would also make the conversion

barrier much lower for web programmers looking to switch to Brython,

if they can continue to use the constructs that they're already

familiar with but just write them in Python instead of JavaScript.

We don't have the same point of view. Mine is to offer an alternative to Javascript, with the simplicity and elegance of the Python syntax, for a programer who wants to develop a web application and doesn't know Javascript. Ultimately this means that the whole DOM API would be described without any mention of Javascript, only with the Python API

With this idea in mind, asking Brython to have a Javascript-like low-level API is like asking CPython to support iteration with a low-level construct like "for i=0;i<10;i++" along with "for i in range(10)". The Python engine is stable enough that we don't have to inspect the bytecode for debugging; similarly, when Brython is mature enough, you won't have to look at the generated Javascript code (which you can do though, eg in the console)
 
P

Pierre Quentel

Le jeudi 20 décembre 2012 01:54:44 UTC+1, Ian a écrit :
It works for me using FF 17.0.1.






+1. The DOM already has a well-established API. The following may

require more typing:



link = document.createElement('a')

link.setAttribute("href", "http://www.python.org/")

link.appendChild(document.createTextNode('Python'))

document.body.appendChild(link)



But it is much clearer in intent. Since these methods map directly to

DOM methods, I know exactly what I expect them to do, and I can look

them up in the browser documentation if I have any doubts. With the

one-liner above, I don't know exactly what that maps to in actual DOM

calls, and so I'm a lot less clear on what exactly it is supposed to

do. I'm not even entirely certain whether it's actually equivalent to

my code above.



I suggest that Brython should have a "low-level" DOM API that matches

up to the actual DOM in as close to a 1:1 correspondence as possible.

Then if you want to have a higher-level API that allows whiz-bang

one-liners like the above, build it as an abstraction on top of the

low-level API and include it as an optional library. This has the

added benefit that if the user runs into an obscure bug where the

fancy API breaks on some particular operation on some specific

browser, they will still have the option of falling back to the

low-level API to work around it. It would also make the conversion

barrier much lower for web programmers looking to switch to Brython,

if they can continue to use the constructs that they're already

familiar with but just write them in Python instead of JavaScript.

We don't have the same point of view. Mine is to offer an alternative to Javascript, with the simplicity and elegance of the Python syntax, for a programer who wants to develop a web application and doesn't know Javascript. Ultimately this means that the whole DOM API would be described without any mention of Javascript, only with the Python API

With this idea in mind, asking Brython to have a Javascript-like low-level API is like asking CPython to support iteration with a low-level construct like "for i=0;i<10;i++" along with "for i in range(10)". The Python engine is stable enough that we don't have to inspect the bytecode for debugging; similarly, when Brython is mature enough, you won't have to look at the generated Javascript code (which you can do though, eg in the console)
 
C

Chris Angelico

I'm afraid I am going to disagree. The document is a tree structure, and today Python doesn't have a syntax for easily manipulating trees. To add a child to a node, using an operator instead of a function call saves a lot of typing ; <= looks like a left arrow, which is a visual indication of the meaning "receive as child". |= doesn't have this arrow shape

This is the reasoning that gave us the C++ stdio system, where:

cout << "Hello, world!\n";

is the way to make console output. Quite frankly, I don't like it;
when I write C++ code, I use printf same as in C. I'd much rather work
with methods than with operators that try to look like the flowing of
data, but actually have a quite different meaning.

ChrisA
 
T

Terry Reedy

What Python does have is 11 versions of the augmented assignment
statement: +=, -=, *=, /=, //=, %=, **=, >>=, <<=, &=, ^=, |=.
Moreover, these are *intended* to be implemented in place, by mutation,
for mutable objects, with possibly class-specific meanings.

We agree. Just use the proper sort of operator. I believe you said
elsewhere that you *are* using one augmented assignment, +=, to add a
sibling. That is a proper use. I am saying to use another to add a child.

<= is a comparison expression operator, which is completely different.
It is just wrong for this usage. I am 99.9% sure you will come to regret
it eventually. Better to make the change now than in Brython2 or Brython3.

If you want to talk shape, I could argue that you should use -= for
adding a sibling (horizontal link, -) and |= for adding a child
(vertical link, |). Since you probably want to stick with += and like
the 'arrowness' of <=, use the augmented assignment operator <<= instead
of comparison operator <=.
 
S

Steven D'Aprano

What Python does have is 11 versions of the augmented assignment
statement: +=, -=, *=, /=, //=, %=, **=, >>=, <<=, &=, ^=, |=. Moreover,
these are *intended* to be implemented in place, by mutation, for
mutable objects, with possibly class-specific meanings.

I don't believe that is the case. The problem is that augmented
assignment that mutates can be rather surprising to anyone who expects
"a += b" to be a short cut for "a = a + b".

py> a = [1, 2, 3]; b = [99]; another = a
py> a = a + b
py> print(a, another) # What I expect.
[1, 2, 3, 99] [1, 2, 3]

py> a = [1, 2, 3]; b = [99]; another = a
py> a += b
py> print(a, another) # Surprise!
[1, 2, 3, 99] [1, 2, 3, 99]


Whichever behaviour you pick, you're going to surprise somebody. So I
wouldn't say that mutate in place is *intended* or preferred in any way,
only that it is *allowed* as an optimization if the class designer
prefers so.

One might even have a class where (say) __iadd__ is defined but __add__
is not.

[...]
<= is a comparison expression operator, which is completely different.

<= is a comparison operator for ints, floats, strings, lists, ... but not
necessarily for *everything*. That's the beauty and horror of operator
overloading. Any operator can mean anything.

If it were intended to only return a flag, then 1) Python would enforce
that rule, and 2) the numpy people would be most upset.

I have no opinion on the usefulness or sensibility of using <= as an in-
place mutator method in this context, but I will say that if I were
designing my own mini-DSL, I would not hesitate to give "comparison
operators" some other meaning. Syntax should be judged in the context of
the language you are using, not some other language. If you are using a
DSL, then normal Python rules don't necessarily apply. <= in particular
looks just like a left-pointing arrow and is an obvious candidate for
overloading.
 
R

Rouslan Korneychuk

I'm afraid I am going to disagree. The document is a tree structure, and today Python doesn't have a syntax for easily manipulating trees. To add a child to a node, using an operator instead of a function call saves a lot of typing ; <= looks like a left arrow, which is a visual indication of the meaning "receive as child". |= doesn't have this arrow shape

+= is supported by Brython, but it means something different. <= means "add child" ; the addition operator + means "add brother"

Although I'm not really in favor of using an operator for this sort of
thing either way, I can't help but notice the discussion seems to be
limited to Python's operators. If you're implementing Python yourself,
can't you define a new operator that is unambiguous?
 
T

Terry Reedy

Although I'm not really in favor of using an operator for this sort of
thing either way, I can't help but notice the discussion seems to be
limited to Python's operators. If you're implementing Python yourself,
can't you define a new operator that is unambiguous?

Then the result is not exactly Python. The Python 3.3 Reference defines
the Python 3.3 language. Supporting only a subset (as Brython does) is
okay as long as the implementation only claims support for a subset (as
Brython does).
 
S

Stefan Behnel

Pierre Quentel, 20.12.2012 10:42:
Le jeudi 20 décembre 2012 01:54:44 UTC+1, Ian a écrit :+1
+1. The DOM already has a well-established API. [...]

link = document.createElement('a')
link.setAttribute("href", "http://www.python.org/")
link.appendChild(document.createTextNode('Python'))
document.body.appendChild(link)

We don't have the same point of view. Mine is to offer an alternative to Javascript, with the simplicity and elegance of the Python syntax, for a programer who wants to develop a web application and doesn't know Javascript. Ultimately this means that the whole DOM API would be described without any mention of Javascript, only with the Python API

If that's your intention, then instead of coming up with something totally
new, unpythonic and ugly, why not take the normal Python route and
implement a subset of the ElementTree API?

Stefan
 
P

Pierre Quentel

If that's your intention, then instead of coming up with something totally
new, unpythonic and ugly, why not take the normal Python route and
implement a subset of the ElementTree API?

Stefan
Because the tree implementation in ElementTree or other tree modules in Python require a lot of typing and parenthesis

To produce the HTML code

<DIV>hello <B>world</B></DIV>

these modules require writing something like

div = Tag('DIV')
div.appendChild(TextNode('hello '))
b = Tag('B')
b.appendChild(TextNode('world'))
div.appendChild(b)
doc.appendChild(div)

With the tree syntax proposed in Brython it would just be

doc <= DIV('hello '+B('world'))

If "pythonic" means concise and readable, which one is more pythonic ?
 
P

Pierre Quentel

If that's your intention, then instead of coming up with something totally
new, unpythonic and ugly, why not take the normal Python route and
implement a subset of the ElementTree API?

Stefan
Because the tree implementation in ElementTree or other tree modules in Python require a lot of typing and parenthesis

To produce the HTML code

<DIV>hello <B>world</B></DIV>

these modules require writing something like

div = Tag('DIV')
div.appendChild(TextNode('hello '))
b = Tag('B')
b.appendChild(TextNode('world'))
div.appendChild(b)
doc.appendChild(div)

With the tree syntax proposed in Brython it would just be

doc <= DIV('hello '+B('world'))

If "pythonic" means concise and readable, which one is more pythonic ?
 
C

Chris Angelico

With the tree syntax proposed in Brython it would just be

doc <= DIV('hello '+B('world'))

If "pythonic" means concise and readable, which one is more pythonic ?

Pythonic also means:
If the implementation is hard to explain, it's a bad idea.

What, exactly, does the sum of a string and a bolded string produce?
Can you explain that easily and clearly? Don't forget that humans, as
well as machines, will expect to be able to parse what's inside the
parentheses without looking outside them.

The DOM structure is, undeniably, quite verbose. But you could go for
something with the same tree structure while a lot less wordy by
simply returning self from lots of methods, thus allowing method
chaining - something like this:

https://github.com/Rosuav/Gypsum/blob/master/window.pike#L247

Note how the tree structure is defined by the parentheses, with
->add(...) calls creating children. (That's Pike, not Python, as I
don't have a good Python example handy. The -> operator does more or
less what Python's . does.) Now, I can conceive of a kind of API - an
ideal API, the creature of my fancy, you know - which would be totally
unobjectionable. An API, for instance, which would abolish taxes and
make everything cheap, except gondolas... oh wait, wrong mailing list.

To produce the HTML code

<DIV>hello <B>world</B></DIV>

you might use:

doc.add(Tag('DIV').add('hello ').add(Tag('B').add('world')))

And you can easily wrap that to suit, since it's surrounded by parentheses:

doc.add(
Tag('DIV')
.add('hello ')
.add(Tag('B').add('world'))
)

There's no magic with operators, just simple method chaining. It's a
bit more verbose than your proposed tree syntax, but not nearly as bad
as the JS version; and it's not magical.

Reject the idea if you will, but do at least please consider it :)

ChrisA
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top