Bdist_apps distribution doesn't execute correctly panda3d 1.10.[7|8] and python 3.8.5

I’m ready to distribute my Panda3D app for testing by some colleagues. I successfully used the the sample asteroids setup.py bdist_apps. The build warned of a few missing modules that I don’t actually use. However, the standalone asteroids app that I built successfully ran on Ubuntu and Windows 10 systems w/o python installed.

I optimistically customized the setup.py and requirements.txt to similarly package my app. I started with my running Panda 1.10.7 on Python 3.9, but found that bdist_apps was using a method that is deprecated in 3.9. So, I built a fresh venv with python 3.8.5, the newest panda3d-1.10.8, and my python code. I got bdist_apps to build with only minor warnings of missing modules. However, nothing seemed to happen when I executed the built executable. Same behavior from the command line and OS GUI; on both Ubuntu and Windows 10.

This is my first experience with building a standalone app. So, I tried a very simple console_app to find the first problem and reduced it to the python below which exhibits an exception that I don’t understand. The following program executes successfully within a Python 3.8.5 environment, but fails in a standalone app built by bdist_apps.

#
print('Hello World')
from pytz import timezone
print('through the import')
home_zone = timezone('US/Eastern')
print('success')
print(f"home_zone={home_zone}, type={type(home_zone)}")


I created the following setup.py:

#
#
from setuptools import find_packages, setup

setup(
    name='build_bug',
    version='0.3',
    author='Dennis Risen',
    author_email='dar5@case.edu',
    description='debugging the bdist process',
    packages=find_packages(),
    classifiers=[
        'Programming Language :: Python :: 3',
        'Operating System :: OS Independent'
        ],
    python_requires='>=3.6',
    options={
        'build_apps': {
             'console_apps': {
                'build_bug': 'build_bug.py'
            },
            'platforms': [
                'manylinux1_x86_64',
                'win_amd64'
            ]
        }
    }
)

and requirements.txt:

pytz

When I run “python setup.py bdist_apps”, it successfully ‘downloaded’ the cached pytz-2021.1, and built standalone distributions while reporting only minor issues:

There are some missing modules: ['UserDict', '__builtin__', '_uuid', 'com.sun', 'com.sun.jna', 'com.sun.jna.platform', 'netbios', 'ordereddict', 'pkg_resources.extern.appdirs', 'pkg_resources.extern.packaging', 'sets', 'win32com.shell', 'win32wnet', 'zipimport']
There are some missing modules: ['_posixsubprocess', 'grp']
warning: build_apps: could not find dependency api-ms-win-crt-utility-l1-1-0.dll (referenced by libcrypto-1_1.dll)

Each standalone distribution executes on its respective system, producing the same output with exception from pytz.timezone:

Hello World
through the import
Traceback (most recent last call):
  File "__main__", line 5, in <module>
  File "pytz", line 188, in timezone
pytz.exceptions.UnknownTimeZoneError: 'US/Eastern'

If pytz is just an oddball that works fine with a normal build, but not with build_apps; I can workaround. However, my app imports a dozen other modules. I’d hate to slug through potential multiple issues due to me just not using a robust technology for building standalone apps. Any advice on robust building of standalone Panda3D apps?

pytz ships with additional data files that need to be explicitly included. Add this to your setup.py:

            'package_data_dirs': {'pytz': [('pytz/zoneinfo/*', 'zoneinfo', ())]}

As for “slugging through potential multiple issues”, this is probably an experience you’ll have with most distribution tools, but the issues are usually of the kind of “a data file or module was not included and needs to be explicitly marked as necessary” and easy to resolve. We’ve tested that the tool works well with many common Python libraries, though, and I’m happy to help you with any other packages that you encounter issues with, since we can update the tool to the benefit of other users as well.

Thanks. pytz packaging problem fixed. Is this class of problem something that a package author can alleviate through additional information in the package’s setup.cfg?

I’m afraid not, because this information doesn’t survive in the metadata that is included in the .whl package.

setup.py bdist_apps built manylinux1_x86_64 and win_amd64 standalone applications. Each app seems to be running correctly, except for some texture handling differences. Initial symptoms are that node.setTexOffset() and/or node.setTexScale() do nothing on both target systems – maybe aren’t finding their textureStage; and my level-of-detail code is applying textures as if the linux screen were tiny. I need to do some debugging, e.g. print() and node.ls() on the target systems.

I start each gui_app from the command line. In linux, the output from e.g. print() functions goes to the terminal, as expected.

However, in Windows, print() output doesn’t display in the initiating cmd window. How do I direct e.g. print() and node.ls() output from the Windows app to the terminal?

GUI apps on Windows can’t output to the console, which is why we provide log_filename to write the output te a log file.

You need to use console_apps instead of gui_apps in setup.py to get console output (and also, don’t set log_filename). The downside of this is that running a console app will always pop up the console, even when not run from the console.

self.win.properties.size is returning a 0 for the window’s x size when running a standalone app in ubuntu.
I took the asteroids sample and inserted a print() into its setKeys() so that I could press a key to see the size value. i.e. I changed setKey to:

    def setKey(self, key, val):
        print(f"self.win.properties.size={self.win.properties.size}")
        self.keys[key] = val

I also modified the setup.py to produce console_apps rather than gui_apps, and commented out the log_filename and log_append lines.

Execution of “python main.py” from my Windows PyCharm terminal, produces the following expect console output resulting my typing a few space characters, then maximizing the window an typing another space

C:\Users\dar5\Google Drive\Case\PyCharm\asteroids>python main.py
Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
self.win.properties.size=LVector2i(800, 600)
self.win.properties.size=LVector2i(800, 600)
self.win.properties.size=LVector2i(800, 600)
self.win.properties.size=LVector2i(1920, 1046)

I built the standalone app for linux and win and tested these on their respective systems.
On windows, the standalone modified asteroids app also outputs outputs reasonable values (for my 4K screen):

Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
self.win.properties.size=LVector2i(800, 600)
self.win.properties.size=LVector2i(800, 600)
self.win.properties.size=LVector2i(800, 600)
self.win.properties.size=LVector2i(3840, 2131)

On Ubuntu, the standalone modified asteroids app outputs the following:

Known pipe types:
  gxlGraphicsPipe
(all display modules loaded.)
self.win.properties.size=LVector2i(0, 600)
self.win.properties.size=LVector2i(0, 600)
self.win.properties.size=LVector2i(0, 600)
self.win.properties.size=LVector2i(0, 1016)

My application displays an array of textured ground-plane tiles (think Google Earth) and arrays of textured building floor-plan tiles for 100+ buildings. The user typically views these at very oblique angles. The app was displaying inappropriate LoD for these. It needs to know the approximate screen size of each such rectangular tile so that it can update the display list with compromise textures and anisotrophy values.

I patched my app with a constant LVector(800, 600) as a temporary work-around.
I didn’t test self.win.properties.size in a normal python environment, because I didn’t want to pollute my virgin test system with python3.x and panda3d installations.

Thanks for your help. My app is working as a gui_apps or console_apps stand-alone app without significant issues beyond pytz and win.properties.size. Other minor issues were:

  • I had listed one of my private pure python modules in my requirements.txt. The standard indexes include a module with the same name, so setuptools dutifully downloaded and installed with the foreign module. Renaming my module or removing it from requirements.txt fixed my bad.
  • Testing the standalone distribution of app found a texture-handling bug in my code that I just hadn’t noticed before.
  • When running “python myapp.py” on Windows the frame rate by default is limited to 60fps (by config.prc?). The standalone app running on a linux laptop cycled at 100–200frames/second. I tried to reduce the excess heat with both
loadPrcFileData('my_app', 'clock-mode M_limited')
loadPrcFileData('my_app', 'clock-frame-rate 30.0')

and

loadPrcFileData('my_app', 'clock-mode limited')
loadPrcFileData('my_app', 'clock-frame-rate 30.0')

Neither had the desired effect, in either the development environment or distribution, of limiting frame rate to 30fps. I needed to use GlobalClock methods instead:

        clock: ClockObject = ClockObject.getGlobalClock()
        clock.setMode(ClockObject.M_limited)
        clock.setFrameRate(30.0)

I recall seeing this on my end; my guess is that it’s enacted by the drivers/GPU-control-panel in Windows.

If it were a PRC setting then I’d expect it to affect both Windows and Linux, I daresay.

Where did you place the calls to “loadPrcFileData”? Did they come before or after you initialised your program?

just before:

aps = Aps()
aps.run()

I take it then that you didn’t put it before the importation of ShowBase? I’m not sure, but the clock-mode settings might be amongst those that only work properly as PRC settings when applied before the importation of ShowBase, if I recall correctly.

I moved those loadPrcFileData to between the imports for loadPrcFileData and ShowBase. This produced a new error that it didn’t like ‘M_limited’. I changed the ‘M_limited’ to ‘limited’ and it worked. Thanks.

from panda3d.core import ConfigVariableManager, loadPrcFileData, NodePath, Plane, LVector3f, LVecBase3f, Point3F
from panda3d.core import WindowProperties
loadPrcFileData('my_app', 'clock-mode limited')
loadPrcFileData('my_app', 'clock-frame-rate 30.0')
from direct.showbase.ShowBase import ShowBase, taskMgr
1 Like

On Windows, the application is likely limited to the vertical refresh rate of your monitor via vsync. I do not remember if Panda requests vsync by default, but your GPU drivers may be defaulting to it. Unfortunately, there is an issue where some GPU drivers will ignore Panda’s request for vsync on Linux: VSync does not work on Linux with NVidia drivers · Issue #963 · panda3d/panda3d · GitHub

1 Like

My linux test laptop has Intel HD 630 controller and NVidia GT107M GPU, which would be consistent with your observation

The window x size problem is really bizarre. I’ve never seen that before. Does it also happen when you call self.win.get_x_size() ?

The frame rate issue might be that it’s choosing a different graphics card (you can check by printing base.win.gsg.driver_renderer, off the top of my head). You can override the driver’s overriding of VSync by setting an environment variable, see the above GitHub link.

I’m OK with setting a frame rate. The window size is odd. I added 2 more print() to the asteroids program’s setKey(), built a distribution for manylinux, and ran it. It produced the following output when I typed a space, then maximized the window, and typed another space:

Known pipe types:
  glxGraphicsPipe
(all display modules loaded.)
self.win.properties.size=LVector2i(0, 600)
self.win.get_x_size()=800, self.win.get_y_size()=600
base.win.gsg.driver_renderer=GeForce GTX 1050/PCIe/SSE2
self.win.properties.size=LVector2i(0, 1016)
self.win.get_x_size()=1848, self.win.get_y_size()=1016
base.win.gsg.driver_renderer=GeForce GTX 1050/PCIe/SSE2

get_*_size() is returning correct values, but properties.size.x is always 0.

In looking more closely at cost-effective deployment of my application on AWS, I’ve changed my plans from deploying the application on EC2 linux instances to EC2 Windows instances with Elastic Graphics (AWS terminology for cost-effective GPU service attached to the instance). So, deploying to linux (or my 4-year old laptop) are not important to me now. I.e. I don’t need the problem solved, but I’m more than willing to assist in clarifying an odd problem that others may encounter.

I’ll install python3.8.7 on the laptop and re-run python source in the python environment, rather than the built distribution.

I found the already installed deb python3.8.5, installed python3-pip, various python tools, and panda3d1.10.8.
The print() output when executing “python3 main.py” was identical to running the standalone distribution built on Windows using setup.py bdist_apps.

properties.size and get_x_size() must be obtaining their results in different ways.

I suspect that it might be a bug; I think that win.properties returns a temporary object whereas properties.size returns a reference, and the reference outlasts the lifetime of the temporary, so it reads from released memory.

If my hunch is true, then using win.properties.get_x_size() instead of win.get_x_size() should also work, and win.size should also work, but that specifically win.properties.size fails.

Furthermore, I expect that storing a reference to the properties should also work:

props = win.properties
print(props.size)

self.win.size correctly returning a LVecBas2i(800, 600).
All of the alternatives work correctly except for self.winproperties.size returning .x=0