Brython - Python in the browser

P

Pierre Quentel

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? Canyou explain that easily and clearly?

Yes : a+b returns the string a+str(b)

It is exactly what you get in CPython with .... def __init__(self,value):
.... self.value = value
.... def __radd__(self,other):
'hello said:
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
Hang me if I understand what this code is supposed to do ;-)
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')))
No, with this syntax, the result of Tag('B').add('world') is below 'hello' in the tree structure, not at the same level (just below Tag('DIV')) as it should be

In this case it's not a real problem, but it's obvious if you want to produce <ul><li>one<li>two</ul> : you would need 2 different 'add'
top = Tag('UL')
top.add(Tag('LI').add('one'))
top.add(Tag('LI').add('two'))

With the syntax used in Brython : UL(LI('one')+LI('two'))

Reject the idea if you will, but do at least please consider it :)
I did in fact consider many options before proposing this one. I have done a lot of web programming, including a web framework, and I faced the problem of generating HTML code from Python. I started with a syntax with nested parenthesis and chained methods returning self, only ending in ugly, unreadable code. Once I started using <= for "add child" and "+" for "add brother" (I first proposed it in the Python Cookbook recipe #366000, the HTMLTags module) - and I've used it on fairly large projects - the result was a much cleaner code
 
P

Pierre Quentel

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? Canyou explain that easily and clearly?

Yes : a+b returns the string a+str(b)

It is exactly what you get in CPython with .... def __init__(self,value):
.... self.value = value
.... def __radd__(self,other):
'hello said:
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
Hang me if I understand what this code is supposed to do ;-)
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')))
No, with this syntax, the result of Tag('B').add('world') is below 'hello' in the tree structure, not at the same level (just below Tag('DIV')) as it should be

In this case it's not a real problem, but it's obvious if you want to produce <ul><li>one<li>two</ul> : you would need 2 different 'add'
top = Tag('UL')
top.add(Tag('LI').add('one'))
top.add(Tag('LI').add('two'))

With the syntax used in Brython : UL(LI('one')+LI('two'))

Reject the idea if you will, but do at least please consider it :)
I did in fact consider many options before proposing this one. I have done a lot of web programming, including a web framework, and I faced the problem of generating HTML code from Python. I started with a syntax with nested parenthesis and chained methods returning self, only ending in ugly, unreadable code. Once I started using <= for "add child" and "+" for "add brother" (I first proposed it in the Python Cookbook recipe #366000, the HTMLTags module) - and I've used it on fairly large projects - the result was a much cleaner code
 
C

Chris Angelico

No, with this syntax, the result of Tag('B').add('world') is below 'hello' in the tree structure, not at the same level (just below Tag('DIV')) as it should be

No; look at the expanded form for a more readable (but syntactically
identical) version:

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

'world' is below Tag('B') - look at the parentheses - but
Tag('DIV').add('hello ') returns the DIV, not the hello, so B and
hello are peers.
In this case it's not a real problem, but it's obvious if you want to produce <ul><li>one<li>two</ul> : you would need 2 different 'add'
top = Tag('UL')
top.add(Tag('LI').add('one'))
top.add(Tag('LI').add('two'))

With the syntax used in Brython : UL(LI('one')+LI('two'))

They can be directly combined, because Tag.add(self,other) returns
self, not other.
Yes : a+b returns the string a+str(b)

'hello <b>world</b>'

Hmm. So when that gets added into a DIV, it has to get parsed for
tags? How does this work? This seems very odd. I would have expected
it to remain as DOM objects.

What happens if I do, for instance:

'blah blah x<y: '+B('True!')

I would expect B('True!') to mean the word "True!" in bold; what
happens with the angle bracket in the text? Am I supposed to manually
escape that as &lt; to protect it? If so, your library isn't doing
much - B might just as well be defined as

lambda s: '<b>'+s+'</b>'

rather than any sort of class.

ChrisA
 
P

Pierre Quentel

<= 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..

I am 99.99% sure of the contrary, having used this syntax for more than 3 years now, as the users of the Karrigell framework with the HTMLTags module

Another point why there is no possible confusion is that when <= is a comparison operator, it is never used in an standalone expression like "a <=b", with the left term of the comparison starting the line ; it is always used in an expression like "if x <= 10", "while x <= 5", "assert x <=0", "return foo <= bar" etc.

So when you see a line like

doc <= DIV('hello')

it should be obvious that you are not *comparing* doc and DIV('hello'), because if it was the case, the line would do nothing
 
P

Pierre Quentel

<= 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..

I am 99.99% sure of the contrary, having used this syntax for more than 3 years now, as the users of the Karrigell framework with the HTMLTags module

Another point why there is no possible confusion is that when <= is a comparison operator, it is never used in an standalone expression like "a <=b", with the left term of the comparison starting the line ; it is always used in an expression like "if x <= 10", "while x <= 5", "assert x <=0", "return foo <= bar" etc.

So when you see a line like

doc <= DIV('hello')

it should be obvious that you are not *comparing* doc and DIV('hello'), because if it was the case, the line would do nothing
 
P

Pierre Quentel

Hmm. So when that gets added into a DIV, it has to get parsed for
tags? How does this work? This seems very odd. I would have expected
it to remain as DOM objects.

In DIV(child) :
- if child is a string, integer or float, a text node is added (addChild) to the DIV element, with the string value of child
- if child is another DOM element (as in DIV(B('foo'))) then this element is added to the DIV element

The code is in module py_dom.js, class $TagClass
What happens if I do, for instance:
'blah blah x<y: '+B('True!')
You can test this code in the console on the Brython site (http://brython.info/tests/console_fr.html) :

doc <= 'blah blah x<y: '+B('True!')

It will add a text node to the document, with the string 'blah blah x<y: ' followed by 'True!' in bold characters

- Pierre
 
P

Pierre Quentel

Hmm. So when that gets added into a DIV, it has to get parsed for
tags? How does this work? This seems very odd. I would have expected
it to remain as DOM objects.

In DIV(child) :
- if child is a string, integer or float, a text node is added (addChild) to the DIV element, with the string value of child
- if child is another DOM element (as in DIV(B('foo'))) then this element is added to the DIV element

The code is in module py_dom.js, class $TagClass
What happens if I do, for instance:
'blah blah x<y: '+B('True!')
You can test this code in the console on the Brython site (http://brython.info/tests/console_fr.html) :

doc <= 'blah blah x<y: '+B('True!')

It will add a text node to the document, with the string 'blah blah x<y: ' followed by 'True!' in bold characters

- Pierre
 
S

Stefan Behnel

Pierre Quentel, 21.12.2012 17:16:
So when you see a line like

doc <= DIV('hello')

it should be obvious that you are not *comparing* doc and DIV('hello'), because if it was the case, the line would do nothing

Yep, that's one of the main concerns - it looks like useless code, which is
totally different from what it does. So it basically uses magic
side-effects as part of the design, which is never a good thing.

Stefan
 
I

Ian Kelly

I am 99.99% sure of the contrary, having used this syntax for more than 3years now, as the users of the Karrigell framework with the HTMLTags module

Another point why there is no possible confusion is that when <= is a comparison operator, it is never used in an standalone expression like "a <= b", with the left term of the comparison starting the line ; it is always used in an expression like "if x <= 10", "while x <= 5", "assert x <= 0", "return foo <= bar" etc.

So when you see a line like

doc <= DIV('hello')

it should be obvious that you are not *comparing* doc and DIV('hello'), because if it was the case, the line would do nothing

The interpreter, though, will be more than happy to treat that as a
comparison if the LHS is not the type that you think it is. For
example, maybe you've added it to a string at some point, and now it's
a string instead of an element. I guess that since doc is made a
keyword, that probably couldn't happen in this example, but it could
happen when trying to add child nodes to other nodes.

By the way, what is Brython actually doing when you append a child to
the document itself like that? Usually I would expect a div to be
appended to the body or to another div. The above looks like it would
attach the new div as a sibling of the html element. Or is it just
calling document.write()?
 
P

Pierre Quentel

The interpreter, though, will be more than happy to treat that as a
comparison if the LHS is not the type that you think it is. For
example, maybe you've added it to a string at some point, and now it's
a string instead of an element. I guess that since doc is made a
keyword, that probably couldn't happen in this example, but it could
happen when trying to add child nodes to other nodes.

Unsurprisingly, the translation engine in Brython transforms x <= y into x.__le__(y)

If x is a string, then __le__ means of course "lesser or equal" so y can only be a string, otherwise an exception is raised ; this is similar to trying to add a child node to a text node in the DOM
By the way, what is Brython actually doing when you append a child to
the document itself like that? Usually I would expect a div to be
appended to the body or to another div. The above looks like it would
attach the new div as a sibling of the html element. Or is it just
calling document.write()?

dom_elt <= obj actually adds one or several DOM nodes (it depends of the class of obj) to the DOM node represented by dom_elt. It's difficult to explain all the cases here, you would have to take a look at the code in py_dom.js, but <= and + work on the DOM tree, there is no document.write anywhere
 
P

Pierre Quentel

The interpreter, though, will be more than happy to treat that as a
comparison if the LHS is not the type that you think it is. For
example, maybe you've added it to a string at some point, and now it's
a string instead of an element. I guess that since doc is made a
keyword, that probably couldn't happen in this example, but it could
happen when trying to add child nodes to other nodes.

Unsurprisingly, the translation engine in Brython transforms x <= y into x.__le__(y)

If x is a string, then __le__ means of course "lesser or equal" so y can only be a string, otherwise an exception is raised ; this is similar to trying to add a child node to a text node in the DOM
By the way, what is Brython actually doing when you append a child to
the document itself like that? Usually I would expect a div to be
appended to the body or to another div. The above looks like it would
attach the new div as a sibling of the html element. Or is it just
calling document.write()?

dom_elt <= obj actually adds one or several DOM nodes (it depends of the class of obj) to the DOM node represented by dom_elt. It's difficult to explain all the cases here, you would have to take a look at the code in py_dom.js, but <= and + work on the DOM tree, there is no document.write anywhere
 
I

Ian Kelly

dom_elt <= obj actually adds one or several DOM nodes (it depends of the class of obj) to the DOM node represented by dom_elt. It's difficult to explain all the cases here, you would have to take a look at the code in py_dom.js, but <= and + work on the DOM tree, there is no document.write anywhere

Thanks, I found my answer in the source: doc <= element basically
calls document.body.appendChild(element)
 
C

Chris Angelico

In DIV(child) :
- if child is a string, integer or float, a text node is added (addChild) to the DIV element, with the string value of child
- if child is another DOM element (as in DIV(B('foo'))) then this element is added to the DIV element

Meaning that:
doc <= <p></p>'
will add literal text, not a paragraph object, right? That's
definitely what I would expect.
doc <= 'blah blah x<y: '+B('True!')

It will add a text node to the document, with the string 'blah blah x<y: ' followed by 'True!' in bold characters

This is where it's getting confusing. My expectation of this is that
it adds a text node with the literal text, followed by a bold node
with its child text. This operation should never involve the parsing
of HTML tags, as the document structure is all there in the code. So
it ought to be a DOM object, not a text string, that gets <='d onto
doc (is <= a verb now?). That means the result of the addition has to
be a DOM object, not a text string; but you said that adding a string
to a B object converts the object to a string and concatenates the
strings.

Do you see now what I mean about the API being difficult to explain?

ChrisA
 
I

Ian Kelly

Meaning that:
doc <= <p></p>'
will add literal text, not a paragraph object, right? That's
definitely what I would expect.


This is where it's getting confusing. My expectation of this is that
it adds a text node with the literal text, followed by a bold node
with its child text. This operation should never involve the parsing
of HTML tags, as the document structure is all there in the code. So
it ought to be a DOM object, not a text string, that gets <='d onto
doc (is <= a verb now?). That means the result of the addition has to
be a DOM object, not a text string; but you said that adding a string
to a B object converts the object to a string and concatenates the
strings.

Do you see now what I mean about the API being difficult to explain?

In my playing around with it just now, the addition doesn't seem to
actually return a string. I typed this script into the test console:

log('hello ' + B('world'))

and clicked Run, and the result was:

[object Object]

whereas if I just try to log a plain string literal, it actually
prints out the string. Somewhat disturbingly, this also gives the
[object Object] result:

log(str('hello ' + B('world')))

In Brython, the str builtin does not return strings?
 
A

Amirouche Boubekki

Héllo,


I will surely backlog latter or some crytologist from the futur will do and
he will surely agree about the fact something strange happened around
december 2012.

Sorry for that, that's me trying to be funny. Last time I checked DOM
manipulation is not the primary way for js devs to do DOM manipulation
anymore, or is it ? Javascript template engines do DOM manipulation but
this is almost invisible for the user so whatever the API, I expect this
will be minor, if not completly overlooked by users of Brython. I could
even argue more that for cross-language knowledge sharing the low level API
should be the same but no.

Brython is a very good idea. I failed at something similar except I took
the pyjs route and focused on classes (functions being callable class
objects) and "bindings" which is IMO more interessant than list
comprehensions, operator-overloading and plain functions. The idea was that
bindings will be even more important than in CPython because most of the
hard work for browser compatibility was already done and optimised by the
JS community. I may completly be off beat but the vision was that Python
would be for framework and application developpement and not for utility
libraries that would replace jQuery, SocketIO, Mediator.js History.js or
any template engine hence the focus on classes and meta-programming.

What is the plan regarding this issues in Brython ?

Regards,


Amirouche
 
I

Ian Kelly

In my playing around with it just now, the addition doesn't seem to
actually return a string.
From the code, it appears that adding two nodes together *actually*
returns a $AbstractTag object, which seems to be just a container for
a list of child nodes with no parent, that automagically gets removed
from the hierarchy when appended to another node.
 
C

Chris Angelico

From the code, it appears that adding two nodes together *actually*
returns a $AbstractTag object, which seems to be just a container for
a list of child nodes with no parent, that automagically gets removed
from the hierarchy when appended to another node.

That actually makes good sense. The sum of two nodes is an ordered
pair of peers, which will be added sequentially to the same parent.
For this to work, *every* situation needs to be able to handle (with
equal ease) a string, an $AbstractTag, or a node.

ChrisA
 
C

Chris Angelico

Last time I checked DOM
manipulation is not the primary way for js devs to do DOM manipulation
anymore, or is it ? Javascript template engines do DOM manipulation but this
is almost invisible for the user...

Not sure how most of the world works, but I write using the DOM.
There's little point using jquery etc when what you're doing is really
simple - which, for me, it is. So I'm probably not representative.

ChrisA
 
S

Steven D'Aprano

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?

Yo mean something old, unpythonic and ugly? :p
 

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

Forum statistics

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

Latest Threads

Top