0

I have a small test page for Brython related tests and recently added xml.etree.Elementree module there, but it doesn't work for some reason.

I've following code (actually there is more stuff but I removed the irrelevant parts):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="/js/jquery-ui-1.12.1/jquery-ui.min.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/js/jquery-ui-1.12.1/jquery-ui.structure.min.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/layout.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/visual.css" media="screen" />
<link rel="stylesheet" type="text/css" href="/js/jquery-ui-1.12.1/jquery-ui.theme.min.css" media="screen" />
<script rel="script" type="text/javascript" src="/js/jquery-3.1.1.min.js"></script>
<script rel="script" type="text/javascript" src="/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
<script rel="script" type="text/javascript" src="/js/brython/brython.js"></script>
<script rel="script" type="text/javascript" src="/js/brython/brython_stdlib.js"></script>
</head>

<body onload='brython()'>
    <script type="text/python" charset="utf-8">
    import sys
    from browser import alert, document as docu
    from browser import ajax
    from xml.etree import ElementTree as ET

    def ajaxReceive(req):
        alert("Input value: " + docu["numinput"].value)
        alert('Ajax response: \n %s' % req.text )
        if req.status == 200 or req.status == 0:
            d = docu['messagebox']
            d.clear()

            r = ET.fromstring(req.text)
            #n = r.findall('./person/name')
            #a = r.findall('./person/age')
            #d.text = 'Dude %s is %s old.' % (n,a)
        else:
            docu['messagebox'] <= 'error: ' + req.text

    def ajaxSend():
        req = ajax.ajax()
        url = '/bryt/'
        x = 1
        y = 2
        z = docu['numinput']

        req.open('POST', url, True)
        req.bind('complete', ajaxReceive)
        req.set_header('content-type', 'application/x-www-form-urlencoded' )
        req.send( {
            'action': 'calc',
            'x': x, 
            'y': y,
            'z': z.value
        })

    docu['ajaxbutton'].bind('click', ajaxSend )

    d = docu['messagebox']
    d.clear()
    d.text = 'ready'
    </script>

    <div id='messagebox' style='width: 20%; border: 1px solid gray; padding: 2em;' >
    </div>
    <br/>

    <input id="numinput" / >
    <br/>
    <br/>
    <button id='ajaxbutton' >Ajax run</button>
</body>
</html>

And at server side it only adds up 3 to given number. The problem is XML-formatted Ajax-response that is being received. It comes in in clear XML, but even building a etree root-element by calling .fromstring() funtion, it tracebacks as follows:

Error 500 means that Python module pyexpat was not found at url http://example.com/bryt/pyexpat.py
brython.js:7171:1
Error 500 means that Python module pyexpat was not found at url http://example.com/bryt/pyexpat/__init__.py
brython.js:7171:1
Error 500 means that Python module pyexpat was not found at url http://example.com/js/brython/Lib/site-packages/pyexpat.py
brython.js:7171:1
Error 500 means that Python module pyexpat was not found at url http://example.com/js/brython/Lib/site-packages/pyexpat/__init__.py
brython.js:7171:1
Error for module xml.parsers.expat
brython.js:7242:21


Error: 
Stack trace:
_b_.ImportError.$factory@http://example.com/js/brython/brython.js line 6466 > eval:49:371
import_hooks@http://example.com/js/brython/brython.js:11605:7
$B.$__import__@http://example.com/js/brython/brython.js:7430:33
$B.$import@http://example.com/js/brython/brython.js:7460:43
$module<@http://example.com/js/brython/brython.js line 7242 > eval:14:9
@http://example.com/js/brython/brython.js line 7242 > eval:1:16
run_py@http://example.com/js/brython/brython.js:7242:1
exec_module@http://example.com/js/brython/brython.js:7276:1
cl_method@http://example.com/js/brython/brython.js:4729:43
import_hooks@http://example.com/js/brython/brython.js:11629:5
$B.$__import__@http://example.com/js/brython/brython.js:7430:33
$B.$import@http://example.com/js/brython/brython.js:7473:5
__init__205@http://example.com/js/brython/brython.js line 7242 > eval:5653:25
type.__call__@http://example.com/js/brython/brython.js:4674:20
factory@http://example.com/js/brython/brython.js:4741:47
XML194@http://example.com/js/brython/brython.js line 7242 > eval:5190:41
ajaxReceive3@http://example.com/js/brython/brython.js line 4294 > eval:176:32
@http://example.com/js/brython/brython.js line 7188 > eval:69:24
ajax.$factory/xmlhttp.onreadystatechange@http://example.com/js/brython/brython.js line 7188 > eval:161:13
brython.js:7243:1
16:21:17.002 args 
Array [ "No module named pyexpat" ]

And there has been something similar in the past brython issue 613 where Pierre states that there is no such thing as pure python pyexpat (July 2017). However Brython standard distribution lists Lib/xml/etree and expat.py - does it mean that it's still not available?

Brython Lib/xml/etreeElementTree.py lines 1511 and onwards starts with:

class XMLParser:

    def __init__(self, html=0, target=None, encoding=None):
        try:
            from xml.parsers import expat
        except ImportError:
            try:
                import pyexpat as expat
            except ImportError:
                raise ImportError(
                    "No module named expat; use SimpleXMLTreeBuilder instead"
                    )

In my understanding it should succeed in first import from xml.parsers import expat but apparently it doesn't when it tries to pyexpat version that does not exist.

So, the question is, has anyone else stumbled into same problem and/or does anyone have a solution for this?


Some addtional (next day) observations:

Cloning and checking out a tag, building from the git repository does not really work as you would expect (no pun intentended).

% git clone https://github.com/brython-dev/brython.git brython.git
% cd brython.git/scripts
brython.git/scripts% python3 ./make_dist.py 
/usr/bin
Traceback (most recent call last):
  File "./make_dist.py", line 207, in <module>
    run()
  File "./make_dist.py", line 88, in run
    import make_stdlib_list
  File "brython.git/scripts/make_stdlib_list.py", line 53, in <module>
    with open(os.path.join(static_doc_folder,lang,'stdlib.html'), 'w', encoding="utf-8") as out:
FileNotFoundError: [Errno 2] No such file or directory: 'brython.git/www/static_doc/en/stdlib.html'
brython.git% 

That is caused by missing directories:

brython.git/scripts% mkdir -p  ../www/static_doc/{en,es,fr}

brython.git/scripts% python3 ./make_dist.py

Very last build lines were:

adding xml.etree
adding xml.etree.cElementTree
adding xml.parsers
adding xml.parsers.expat
adding xml.sax

So maybe those are included.

Once targets are created, they (apparently, not really sure) appear into brython.git/setup/data directory, release zip files and naked .js files for live website. So I link into that directory in my Apache httpd webroot. But that building did not solve the traceback problem.

As side note, for an old OpenSource fart as myself, I feel very alien in this source tree, this project is done in Mouse camp (Microsoft Windows) and even one rare Makefile I managed to find, does not work with GNU Make because conflicting use of whitespace. Let alone there would be regular INSTALL, README, setup, Makefile etc files with expected content. I'm literally reading sources and guessing how all this is supposed to work. But I guess that only tells that Python is truely a cross platform language.

As being an "Open Source project", it's funny that its discussion is not for everyone: Your application to join the Google group brython has been refused

Juha Tuomala
  • 111
  • 11

2 Answers2

1

The answer from the Issue is still relevant. Expat is a C-library which can't be used. You'll need to make do with window.DOMParser.

The preferred way to use brython is not via cloning the repo, but using pip:

$ pip install brython

and then

$ python3 -m brython install

in the directory where you are developing your app. This will copy all the necessary javascript files and create an example app from which you can start.

Note that this is all described in the "nonexistent" README.md file.

jonathanverner
  • 303
  • 3
  • 12
  • Maybe that is preferred way in Windows, but not in systems that has working Software Management System for everything. Solaris, HP-UX, BSD, Linux users in my experience don't use pip for good reason and hence don't even know how to use it. – Juha Tuomala Apr 11 '18 at 08:16
  • 1
    Actually, I haven't used windows for over 15 years. Pip is standard for Python (on Windows, Linux, and everywhere else). __Users__ of the library should use pip. Cloning the source is for people __developing Brython__ (or for people, who know about how it works and want to do something specific). Oh, and btw, in general, language specific packaging systems (vs system provided ones like apt, rpm, ...) can make very good sense. See, e.g., https://rbtcollins.wordpress.com/2012/08/27/why-platform-specific-package-systems-exist-and-wont-go-away/ – jonathanverner Apr 12 '18 at 09:25
0

Well, digging deeper and it appears that Lib/xml/parses/expat.py contains:

"""Interface to the Expat non-validating XML parser."""
import sys

from pyexpat import *

# provide pyexpat submodules as xml.parsers.expat submodules
sys.modules['xml.parsers.expat.model'] = model
sys.modules['xml.parsers.expat.errors'] = errors

I tried to comment that pyexpat part and rebuild the pkgs, the traceback is now different. So there is no expat, no pyexpat and no ElementTree then. No XML in Ajax responses then.

Juha Tuomala
  • 111
  • 11