Guide to Pyjs and Pyjsdl

These notes provide instructions on the use of Pyjs with Pyjsdl, which were tested on Linux and Win7 systems.

Installation of Pyjs 0.8.1-dev is required, currently available from Pyjs Github repository. Check instruction on Pyjs Github site.

The tools required for installation are pip and git, install tools if necessary from package manager (Linux) or follow install instructions on tools Webpage (Win7).
Linux:
sudo apt-get install python-pip
sudo apt-get install git

Command to install Pyjs with pip:
Linux system install:
sudo pip install git+https://github.com/pyjs/pyjs.git#egg=pyjs
Linux local install:
pip install git+https://github.com/pyjs/pyjs.git#egg=pyjs --user
Win7:
pip install git+https://github.com/pyjs/pyjs.git#egg=pyjs

With Pyjs installed, pyjsbuild had error 'pkg_resources.DistributionNotFound: six', resolved after Pyjs install by upgrading Six dependency:
pip show six (upgrade version 1.3 to 1.8)
Linux:
sudo pip install six --upgrade
Win7:
easy_install --upgrade six

Command to show information of Pyjs installed by pip:
pip show pyjs
>
Linux information:
Location: /local/lib/python2.7/site-packages/
Win7 information:
Location: \python27\lib\site-packages

Location of pyjsbuild and pyjscompressor:
Linux:
/local/bin/
Win7:
\python27\scripts
Refer to these scripts with system path, instances below are in Linux.

To get HTML5 Canvas to work with IE9+, modify Pyjs as described in pyjsdl/guide.txt:
Use files in pyjs_changes.zip/git-140806 to modify or overwrite the following files:
Linux change:
/local/lib/python2.7/site-packages/pyjs/browser.py
/local/lib/python2.7/site-packages/pyjs/boilerplate/home.nocache.html
Win7 change:
\python27\lib\site-packages\pyjs\browser.py
\python27\lib\site-packages\pyjs\boilerplate\home.nocache.html

Use pyjsbuild to compile, check 'pyjsbuild --help' for command options. Use compile options -S (strict mode), -O (optimise mode), and -d (debug). Use of --dynamic-link option links JavaScript files in lib folder, decreasing size of browser specific HTML files and permitting shared lib folder with multiple demo apps. Use the -o option to build to separate output folder for different option set. To test installed Pyjs, compile an app from Pyjs examples, which can be downloaded from Pyjs Github repository. Not all examples work, but tested the following:

Helloworld App
change to folder /examples/helloworld
/local/bin/pyjsbuild -S Hello.py --dynamic-link -o output

GWTCanvas App
change to folder /examples/gwtcanvas
/local/bin/pyjsbuild -S GWTCanvasDemo.py --dynamic-link -o output

Compile a Pyjsdl demo with Pyjs and Pyjsdl, download demo app and unpack. Download Pyjsdl and unpack, placing Pyjsdl folder in the demo app folder. Compile the script with the command:
/local/bin/pyjsbuild -O serpentduel.py --dynamic-link -o output
Following build, place data folder containing images in output folder.
Tested by opening app.html in Firefox, IE, and Chrome.
To open local files, launch Chrome with the option --allow-file-access-from-files
Can use a local server, such as SimpleHTTPServer with command:
python -m SimpleHTTPServer 8000
Server root folder is where command was run, use browser at http://localhost:8000 to browse to HTML file to load.

Use pyjscompressor to compress JavaScript in output folder with command:
python /local/bin/pyjscompressor output
Pyjscompressor uses Closure Compiler, can download latest release and use:
python /local/bin/pyjscompressor output -c compiler.jar
Pyjscompressor did not work in Pyjs build 140806, with 'ImportError: No module named contrib.pyjscompressor', due to missing files apparently left out during installation. Resolved by downloading Pyjs from Pyjs Github repository, and copy missing files from /pyjs/contrib/ to /local/lib/python2.7/site-packages/pyjs/contrib/ (Linux) or \python27\lib\site-packages\pyjs\contrib\ (Win7).

Following compilation with pyjsbuild and optional compression with pyjscompressor, the output folder containing the app can be deployed to a Web server.

This entry was posted in Programming and tagged , , , , , . Bookmark the permalink. Trackbacks are closed, but you can post a comment.

32 Comments

  1. Bob
    Posted 2021/03/01 at 21:11 | Permalink

    This worked until i tried to open the html file. It said" serpentduel ImportError: No module named pyjsdl, pyjsdl in context None". How can i fix this?

    Reply

    • Posted 2021/03/01 at 21:45 | Permalink

      You should make sure you have pyjs installed properly and can compile a program, try to compile and run a pyjs example app such as /examples/helloworld mentioned in this post.

      Reply

    • Posted 2021/03/01 at 22:25 | Permalink

      Regarding the importerror, the browser reports the error if the demo is pyjs compiled with pyjsdl absent. Ensure the pyjsdl folder is in the demo folder then compile.

      Reply

      • Bob
        Posted 2021/03/01 at 22:43 | Permalink

        Ok thank you. I had accidently kept the pyjsdl folder inside pyjsdl-0.22. I removed it and the website had loaded, and the starting screen for the serpent duel came up. However, when I click on it, the game does not start.

        Reply

        • Posted 2021/03/01 at 22:45 | Permalink

          Probably need to move the data folder into the pyjs output folder.

          Reply

          • Bob
            Posted 2021/03/01 at 22:47 | Permalink

            Oh sorry I forgot. Thank you it works perfectly now.

            Reply

  2. jee
    Posted 2021/03/27 at 00:53 | Permalink

    serpent.py works fine with the instructions above.
    When I try to run my code, it gives me the error, "ImportError: No module named pandas". How do i fix this?

    Reply

    • Posted 2021/03/27 at 02:29 | Permalink

      I suspect you meant that you got an importerror with pyjamas module that is part of pyjs, seen this error if the script is run with python. The script should be compiled by pyjs to javascript and run in the browser.

      Reply

  3. Lordofgobgbos
    Posted 2021/03/31 at 17:04 | Permalink

    When I try to run serpentduel, it returns :
    rTaceback (most recent call last):
    File "serpentduel.py", line 29, in
    import pyjsdl as pygame #pyjsdl import
    File "/home/lordofgobgobs/Games/pyjsdl/__init__.py", line 25, in
    from pyjsdl import util
    File "/home/lordofgobgobs/Games/pyjsdl/util.py", line 4, in
    from pyjsdl.time import Time
    File "/home/lordofgobgobs/Games/pyjsdl/time.py", line 6, in
    from __pyjamas__ import JS
    ModuleNotFoundError: No module named '__pyjamas__'

    Reply

    • Posted 2021/03/31 at 17:28 | Permalink

      Ensure you compiled the script with pyjsbuild and run in the web browser.

      Reply

      • Lordofgobgobs
        Posted 2021/04/01 at 12:18 | Permalink

        Oh. How do I do that

        Reply

        • Posted 2021/04/01 at 12:29 | Permalink

          Instructions are in this post and more info on pyjsdl page. The first step is to install pyjs from github as described in this post and then ensure it is functional by compiling and running some pyjs examples. Once everything is working, check guide.txt in pyjsdl package, then should be able to compile the pyjsdl demo.

          Reply

          • Lordofgobgbos
            Posted 2021/04/01 at 13:18 | Permalink

            Yes, but how do I compile the examples?

            Reply

          • Posted 2021/04/01 at 13:24 | Permalink

            This guide post has the instruction, install pyjs and then use pyjsbuild to compile, such as:
            pyjsbuild -S Hello.py.

            Reply

          • Lordofgobgobs
            Posted 2021/04/01 at 14:34 | Permalink

            It always tells me :
            -bash: pyjsbuild: command not found

            Reply

          • Posted 2021/04/01 at 18:58 | Permalink

            Perhaps provide more info on what you have done. First step is to install pyjs, make sure this is installed from its github repository as this version is required for pyjsdl. Pyjs is still at python2, so you need to install with python2 + pip. This guide post describes the install procedure as well as the location of pyjsbuild after pyjs installation. Further install info is on pyjs github repository page.

            Reply

  4. Will
    Posted 2022/02/01 at 01:24 | Permalink

    I'm running into an issue where my image files are not loading. I'm receiving an error on chrome when running via a 'python -m SimpleHTTPServer' of 'error: Failed to retrieve image file'.

    I'm loading them the same method as the serpentduel script and preloading before hand. But was wondering if there might be another issue causing it. Thanks!

    Reply

    • Posted 2022/02/01 at 02:40 | Permalink

      The error occurs when the specified image has not been preloaded and cached. Several possible reasons for the error. Check chrome devtools console to ensure there is no error with image retrieval. Ensure image folder is in the output folder, image path uses forward slash, and that image path used in preloading is same as that of image.load. Also, the image preloading needs to occur after display.set_mode but before image.load. Hope this helps.

      Reply

      • Will
        Posted 2022/02/01 at 11:08 | Permalink

        Thanks for the quick reply! So I took a look at the dev tools and couldn't find anything of interest. It looks like the browser isn't even attempting to load the images (no calls to retrieve). This is currently the code in my main function:

        pygame.init()
        pygame.display.set_caption('App')
        screen = pygame.display.set_mode((1600, 800))
        images = ['./data/airship.png', './data/destination.png', './data/earth.png']
        pygame.display.setup(run(screen), images)

        and the run() function is what eventually calls the image.load('./data/airship.png'). After I compile the script, I move the data folder into the output folder but am still met with this error.

        Reply

        • Posted 2022/02/01 at 13:16 | Permalink

          During development, as browsers cache web pages, empty browser cache to ensure that your code changes are loaded in the browser - alternatively rather than to empty cache every time, load your app page with devtools open with settings 'disable cache while devtools is open'. Now to the issue, the function pyjsdl.display.setup (or pyjsdl.setup) takes a callback function without arguments. The screen variable needs to be passed another way, either by placing it in global space or code your own function/method and pass it as an argument as done in serpentduel. See the post Compile Apps with Pyjs and Pyjsdl for more info. For your code, try:

          screen = None
          
          def setup():
            global screen
            pygame.init()
            pygame.display.set_caption('App')
            screen = pygame.display.set_mode((1600, 800))
          
          setup()
          images = ['./data/airship.png',
                    './data/destination.png',
                    './data/earth.png']
          pygame.setup(run, images)
          

          Reply

          • Will
            Posted 2022/02/01 at 15:04 | Permalink

            Awesome that solved the picture loading issue, thanks so much! I now seem to be met with a blank white screen with console errors racking up claiming "Uncaught TypeError: screen.blit is not a function"

            did transferring the screen to a global variable cause a blit error or is this something I'll have to alter with the transfer from pygame to pyjsdl? Sorry for all the questions!

            Reply

          • Posted 2022/02/01 at 15:55 | Permalink

            Not sure. The display.set_mode method returns a surface object with a blit method. The error message suggests it cannot find the blit method, make sure there is no syntax error there. Also, ensure the screen object is passed properly. With 'pyjsbuild -S' (or 'pyjsbuild -O --enable-print-statements') you can debug with print that outputs to console: before the screen.blit call do a print(screen) or print(dir(screen)) that should output surface object info to console. If a problem is detected there, do as the serpentduel demo, rather than use of a global variable the screen object is passed to the matrix object as an argument.

            Reply

          • Will
            Posted 2022/02/01 at 17:31 | Permalink

            Alright so printed the screen out at various points to make sure it was being passed correctly and looks as if it is. I'm getting a
            "[object Screen]" when calling print(screen) and "['availWidth', 'availHeight', 'width', 'height', 'colorDepth', 'pixelDepth', 'availLeft', 'availTop', 'orientation']" when calling print(dir(screen)) so i'm still a little confused as to why it cant find the function. My statement where I call it looks like this:

            self.frame_string = " " + frame + " Frame"
            self.frame_text = font.render(str(self.frame_string), True, (11, 252, 3))
            self.frame_rect = self.frame_text.get_rect(topleft=(0, 0))
            screen.blit(self.frame_text, self.frame_rect)

            Reply

          • Posted 2022/02/01 at 18:50 | Permalink

            The object printed is a Screen object not a Surface object. Personally have not seen this, apparently your code is referencing the browser's javascript screen object. A quick fix may be to rename screen variable returned by display.set_mode, but may be better to pass it to your object as an argument rather than using a global variable.

            Reply

          • Will
            Posted 2022/02/02 at 09:38 | Permalink

            Ok so I renamed the global variable to surface and pushed up the initialization of it in the file and it seems to have fixed it (I'm using Brave as my main browser so i'm wondering if there was something funky with the browsers screen object) and all of my other print statements are being reached now. The only other issue I have left is that nothing is being drawn on the screen. Its all white even though I know my print statements are being reached and all the info looks correct. The serpentduel demo runs fine though and I'm utilizing the same blit methods.

            Reply

          • Posted 2022/02/02 at 13:04 | Permalink

            May be better to develop in chrome or firefox, later check if it runs properly with brave. In development, pyjsbuild with -S option and -d debug option, later can move to -O option that compiles optimize javascript but sacrificing some python compatibility such as rect virtual attributes.

            Frustrating to have an app running incorrectly without showing an error, but that is the evil of javascript programs. That is the power of pyjsdl, code in python/pygame to have a working program, then translate to a javascript app. Your issue suggests that images are not being loaded with image.load but the browser will blit undefined objects without complaint. You have to trace things, do print(image) after image.load to confirm it is a surface object. I would need to see some code to suggest anything specific, either provide a small code snippet or a link to code, or dm if preferred.

            Check pyjsdl-ts, which has the same functionality as pyjsdl, using transcrypt that is python3.9-compatible and generates optimized javascript. Since you started with pyjsdl, may want to continue as similar code changes need to be done as pyjsdl-ts.

            Reply

          • Will
            Posted 2022/02/03 at 19:58 | Permalink

            Here's the repo to what I'm currently working on:

            https://github.com/wjk36/senior-project

            specifically the main_earth.py which is the script im executing. I tried printing the images after load and Its showing a surface that is the correct size. But nothing is still showing up when executing.

            Reply

          • Posted 2022/02/03 at 22:22 | Permalink

            Checked your code, I did 'pyjsbuild -S main_earth.py' using test images and was able to get space displayed and rocket navigation. To use pyjsdl, there are three key changes: pyjsdl import, image preload, and change of the main loop to a callback. The browser cannot do a continuous loop as javascript environment is single threaded and would block display update. The 'while running' loop needs to be changed:

            def run_sim():
              global pausing, running
              for event in pygame.event.get():
              ...
              clock.tick(25)
            
            clock = font = ... = speed_list = None
            
            def run():
              global clock, font, ..., speed_list
              clock = pygame.time.Clock()
              font = pygame.font.SysFont(None, 32)
              ...
              speed_list = []
              pygame.set_callback(run_sim)
            
            def main():
              setup()
              images = [...]
              pygame.setup(run, images)
            

            The 'run' callback initiates the variables, placed in global space to share between callbacks. The 'run_sim' function revised the main loop to a callback to be called with browser update. Setting callback functions can be chained, set to 'run' then changed to 'run_sim', if just changing callback able to use pygame.set_callback instead of pygame.setup.

            Once things are working, can get performance with pyjsbuild -O, though some python compatibility is lost such as rect virtual attributes that need to be edited, check pyjsdl documentation.

            Reply

          • Will
            Posted 2022/02/04 at 12:50 | Permalink

            Ah thank you so much! I was able to get it working with the fixes you gave me. Thanks immensely for the help and the module!

            Reply

          • Posted 2022/02/05 at 14:09 | Permalink

            Glad to help.

            Reply

          • Will
            Posted 2022/02/08 at 17:58 | Permalink

            Final question, when compiled as is, the html generates a div at the bottom of the page no matter what. I was wondering how you were able to format/style your game once you compiled the html. I would like it to be generated in its own div with a id/class I give it but its always its own blank div at the bottom of the html.

            Thanks

            Reply

          • Posted 2022/02/08 at 22:24 | Permalink

            The post Deploy JavaScript Application Using Pyjsdl shows how to embed the app into a div on a web page that can be styled. To directly style the div element with the child canvas, the following code will set div id to 'mycanvas', which would permit the use of css to set style, or use querySelector to retrieve the element to style in code:

            pg.display.set_mode((400,400))
            canvas_obj = pg.display.get_canvas()
            canvas_obj.setID('mycanvas')
            
            panel = pg.display.get_panel()
            el = panel.getElement()
            div = el.querySelector('#mycanvas')
            div.style.border = 'thick solid #0000ff'
            canvas = el.querySelector('#mycanvas canvas')
            canvas.style.border = 'thin solid #ff0000'
            

            Reply

Post a Reply to Lordofgobgbos Cancel reply

Your email is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*