I have a file, Foo.py which holds the code below. When I run the file from command line using, python Foo.py everything works. However, if I use CLI of python
python
import Foo
Foo.main()
Foo.main()
Foo.main()
The first call works fine, the second brings forward all hell of warnings, the first of which is
(python:5389): Gtk-CRITICAL **: IA__gtk_container_add: assertion 'GTK_IS_CONTAINER (container)' failed
And the last cause a segmentation fault. What's the problem with my code?
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import os
from PyQt4 import Qt
from PyQt4 import QtGui,QtCore
class Foo (QtGui.QWidget):
def __init__(self,parent=None):
super(Foo,self).__init__()
self.setUI()
self.showMaximized()
def setUI(self):
self.setGeometry(100,100,1150,650)
self.grid = QtGui.QGridLayout()
self.setLayout(self.grid)
#For convininece, I set different ui "concepts" in their own function
self.setInterfaceLine()
self.setMainText()
def setMainText(self):
#the main box, where information is displayed
self.main_label = QtGui.QLabel('Details')
self.main_text = QtGui.QLabel()
self.main_text.setAlignment(QtCore.Qt.AlignTop)
#Reading the welcome message from file
self.main_text.setText('')
self.main_text.setWordWrap(True) #To handle long sentenses
self.grid.addWidget(self.main_text,1,1,25,8)
def setInterfaceLine(self):
#Create the interface section
self.msg_label = QtGui.QLabel('Now Reading:',self)
self.msg_line = QtGui.QLabel('commands',self) #the user message label
self.input_line = QtGui.QLineEdit('',self) #The command line
self.input_line.returnPressed.connect(self.executeCommand)
self.grid.addWidget(self.input_line,26,1,1,10)
self.grid.addWidget(self.msg_label,25,1,1,1)
self.grid.addWidget(self.msg_line,25,2,1,7)
def executeCommand(self):
fullcommand = self.input_line.text() #Get the command
args = fullcommand.split(' ')
if fullcommand =='exit':
self.exit()
def exit(self):
#Exit the program, for now, no confirmation
QtGui.QApplication.quit()
def main():
app = QtGui.QApplication(sys.argv)
foo = Foo(sys.argv)
app.exit(app.exec_())
if __name__ in ['__main__']:
main()
I'm able to reproduce in Python 3 but not Python 2.
It's something about garbage collection and multiple QApplications. Qt doesn't expect multiple QApplications to be used in the same process, and regardless of whether it looks like you're creating a new one every time, the old one is living on somewhere in the interpreter. On the first run of your main() method, You need to create a QApplication and prevent it from being garbage collected by storing it somewhere like a module global or an attribute to a class or instance in the global scope that won't be garbage collected when main() returns.
Then, on subsequent runs, you should access the existing QApplication instead of making a new one. If you have multiple modules that might need a QApplication but you don't want them to have to coordinate, you can access an existing instance with QApplication.instance(), and then only instantiate one if none exists.
So, changing your main() method to the following works:
def main():
global app
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication(sys.argv)
foo = Foo(sys.argv)
app.exit(app.exec_())
It's odd you have to keep a reference to ensure the QApplication is not garbage collected. Since there is only supposed to be one per process, I would have expected it to live forever even if you don't hold onto a reference to it. That's what seems to happen in Python 2. So ideally the global app line would not be needed above, but it's there to prevent this garbage collection business.
We're kind of stuck in the middle about how immortal this QApplication object is ... it's too long lived for you to be able to use a new one each time, but not long-lived enough on its own for you to re-use it each run without having to prevent its garbage collection by holding onto a reference. This might be bug in PyQt, which probably ought to do the reference holding for us.
There must be only on QApplication instance in one process. GUI frameworks are not prepared for multi-application mode.
I can't actually reproduce the problem, which at least shows there's nothing fundamentally wrong with the code.
The problem is probably caused by some garbage-collection issues when the main function returns (the order of deletion can be unpredictable).
Try putting del foo after the event-loop exits.
Related
I am attempting to use a module named "global_data" to save global state information without success. The code is getting large already, so I`ll try to post only the bare essentials.
from view import cube_control
from ioserver.ioserver import IOServer
from manager import config_manager, global_data
if __name__ == "__main__":
#sets up initial data
config_manager.init_manager()
#modifies data
io = IOServer()
#verify global data modified from IOServer.__init__
global_data.test() #success
#start pyqt GUI
cube_control.start_view()
So far so good. However in the last line cube_control.start_view() it enters this code:
#inside cube_control.py
def start_view():
#verify global data modified from IOServer.__init__
global_data.test() #fail ?!?!
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
Running the global_data.test() in this case fails. printing the entire global state reveals it now somehow reverted back to the data setup by config_manager.init_manager()
How is this possible?
While Qt is running I have a scheduler called every 10 seconds, also reporting a failed test.
However once the Qt GUI is stopped (clicked "x"), and I run the test from console, it succeeds again.
Inside the global_data module I`ve attempted to store the data in a dict inside both a simple python object as well as a ZODB in memory database:
#inside global_data
state = {
"units" : {}
}
db = ZODB.DB(None) #creates an in memory db
def test(identity="no-id"):
con = db.open()
r = con.root()
print("test online: ", r["units"]["local-test"]["online"], identity)
con.close()
Both have the exact same problem. Above the test is only done using the db.
The reason I attempted to use a db is that I understand threads can create a completely new global dictionary. However the 2 first tests are in the same thread. The cyclic one is in its own thread and could potentially create such a problem...?
File organization
If it helps my program is organized with the following structure:
There is also a "view" folder with some qt5 GUI files.
The IOServer attempts to connect to a bunch of OPC-UA servers using the opcua module. No threads are manually started there, although I suppose the opcua module does to stay connected.
global_data id()
I attempted to also print(id(global_data)) together with the tests and found that the ID is the same in IOServer AND top level code, but changes inside the cube_control.py#start_view. Should not these always refer to the same module?
I`m still not sure what exactly happened. But apparently this was solved by removing the init.py file inside of the folder named manager. Now all imports of the module named "global_data" points to the same ID.
How using a init.py file caused a second instance of the same module remains a mystery
Basically, my code in top.py is like this. I am trying to create a PyQt5 project, and be able to test each dialog boxes / windows separately.
import sys, os
if __name__ == '__main__':
os.chdir('../')
sys.path.insert(0,'.')
#import *
else:
pass
#from . import *
#from common import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
def main():
global window
window = MainWindow()
window.showUI()
class MainWindow(QWidget):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
def showUI(self):
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
main()
sys.exit(app.exec_())
Is it a bad practice?
Project structure:
main.py
gui/
__init__.py
top.py
common/
__init__.py
common.py
A common design which is however technically completely optional is something like
def real_stuff():
# ... your actual code ...
def main():
# some setup when invoked from the command line
# maybe print a hostile welcome message? (No, don't.)
real_stuff()
if __name__ == '__main__':
main()
The purpose of the final conditional is to make your script possible to import from another script, but also possible to run with python from the command line. When you import you don't want the program to start running immediately, so the starting point is conditional on that.
You could basically put everything you have in def main(): inside if __name__ == '__main__': instead and it would work completely the same. When it's not completely trivial it's nice to have it encapsulated in a separate function so that a human reader has an easier time following the logic, but as far as Python is concerned, it's pretty much the same (apart from the trivial overhead of one additional function call).
A tangential consideration is how to make your code modular enough to be reusable. If real_stuff() is a useful piece of functionality which you may want to call from other programs in the future, definitely make it into a separate function which is not inside def main() or even inside if __name__ == '__main__'. If it has snippets which could be useful for other programs in their own right, refactor those into separate functions, too, and call those when you need them from your other programs, too.
For these function to be programmatically useful, they should probably not do any user-facing interactions, so probably factor those into a separate function -- again, not necessarily inside main() but separate from the code which makes sense to use from other programs in the future. Whatever remains of user interaction or startup for the code to run standalone, put in main() (or, again, if it's completely trivial, don't even create a separate function for it).
A good practice would be to have a "test" folder with one file per "window" to be tested. For example a "toy_test.py" file where you import all what is needed, such as "toy.py". And cut and paste the main block in this test file.
But the way you did is correct as "if main" block is invoked only if the script is the one being directly invoked.
I'm working on a pygame project and have the main engine layed out. The problem is I hit a bug that I just can not seem to figure out. What happens is one module can't read a variable from another module.
It's not that the variable can't be read, it just sees an empty list instead of what it really is.
Instead of posting the entire source code I reproduced the bug in two small snippets that hopefully a skillful python-ist can interpret in his\her head.
Code:
main.py (This is the file that gets run)
import screen
screens = [] #A stack for all the game screens
def current_screen():
#return a reference to the current screen
return screens[-1]
def play():
print'play called'
current_screen().update()
if __name__=='__main__':
screens.append(screen.Screen())
play()
screen.py
import main
class Screen:
def __init__(self):
print'screen made'
def update(self):
print main.screens
#Should have a reference to itself in there
Thanks!
Don't import the main script. When you run the main.py file directly, it becomes the __main__ module. When you then import main, it will find the same file (main.py) but load it a second time, under a different module object (main instead of __main__.)
The solution is to not do this. Don't put things you want to 'export' to other modules in the main script. It won't work right. Put them in a third module. Or, pass them as arguments to the functions and classes you're calling.
The whole point of if __name__=='__main__': is to prevent code from being run when a module is imported. So when you import main from screen, that part isn't run and the list stays empt and play() is never called either.
I'm using a modified version on juno (http://github.com/breily/juno/) in Google App Engine. The problem I'm having is I have code like this:
import juno
import pprint
#get('/')
def home(web):
pprint.pprint("test")
def main():
run()
if __name__ == '__main__':
main()
The first time I start the app up in the dev environment it works fine. The second time and every time after that it can't find pprint. I get this error:
AttributeError: 'NoneType' object has no attribute 'pprint'
If I set the import inside the function it works every time:
#get('/')
def home(web):
import pprint
pprint.pprint("test")
So it seems like it is caching the function but for some reason the imports are not being included when it uses that cache. I tried removing the main() function at the bottom to see if that would remove the caching of this script but I get the same problem.
Earlier tonight this code was working fine, I'm not sure what could have changed to cause this. Any insight is appreciated.
I would leave it that way. I saw a slideshare that Google put out about App Engine optimization that said you can get better performance by keeping imports inside of the methods, so they are not imported unless necessary.
Is it possible you are reassigning the name pprint somewhere? The only two ways I know of for a module-level name (like what you get from the import statement) to become None is if you either assign it yourself pprint = None or upon interpreter shutdown, when Python's cleanup assigns all module-level names to None as it shuts things down.
I'm sorry for the verbal description.
I have a wxPython app in a file called applicationwindow.py that resides in a package called garlicsimwx. When I launch the app by launching the aforementioned file, it all works well. However, I have created a file rundemo.py in a folder which contains the garlicsimwx package, which runs the app as well. When I use rundemo.py, the app launches, however, when the main wx.Frame imports a sub-package of garlicsimwx, namely simulations.life, for some reason a new instance of my application is created (i.e., a new identical window pops out.)
I have tried stepping through the commands one-by-one, and although the bug happens only after importing the sub-package, the import statement doesn't directly cause it. Only when control returns to PyApp.MainLoop the second window opens.
How do I stop this?
I think you have code in one of your modules that looks like this:
import wx
class MyFrame(wx.Frame):
def __init__(...):
...
frame = MyFrame(...)
The frame will be created when this module is first imported. To prevent that, use the common Python idiom:
import wx
class MyFrame(wx.Frame):
def __init__(...):
...
if __name__ == '__main__':
frame = MyFrame(...)
Did I guess correctly?
You could create a global boolean variable like g_window_was_drawn and check it in the function that does the work of creating a window. The value would be false at the start of the program and would change to True when first creating a window. The function that creates the window would check if the g_window_was_drawn is already true, and if it is, it would throw an exception. Then You will have a nice stacktrace telling You who is responsible of executing this function.
I hope that helps You find it. I'm sorry for the verbal solution ;)
Got it: There was no
if __name__=='__main__':
in my rundemo file. It was actually a multiprocessing issue: The new window was opened in a separate process.