How can I debug a single class? - python

I'm writing a code on PyCharm, but it is easier for me if I could debugg continually while I'm writing my code. I can't figure out, that how do I get this class debugged? :
from PyQt5.Qt import QGraphicsPixmapItem
from PyQt5.QtGui import QPixmap
class Level():
def __init__(self, scene, level):
self.scene = scene
self.level = open(level)
def add_item_to_scene(self):
for x in range(self.level):
for y in range(self.level[0]):
if y == 'X':
brick = QPixmap('brick.png')
self.scene.addItem(brick)
I have just begun and this is all what I've written. I'm doing a Platformer game with PyQt5, and I'm trying to set the levels now. Thank you for any help.

Use a convention to run code during development and not run the code on import as shown in the following code.
from PyQt5.Qt import QGraphicsPixmapItem
from PyQt5.QtGui import QPixmap
class Level():
def __init__(self, scene, level):
self.scene = scene
self.level = open(level)
def add_item_to_scene(self):
for x in range(self.level):
for y in range(self.level[0]):
if y == 'X':
brick = QPixmap('brick.png')
self.scene.addItem(brick)
# Use the following convention.
# In python the initial module run receives the name __main__.
if __name__ == '__main__':
print(f'Hello my name is {__name__=} because my module was started by '
f'pyhton. ')
# So while developing whenever you run this module commands here will run.
# Later on when you import the module the commands will not run.
# because __main__ will be the name of this module
l = Level('brick', 5)
l.add_item_to_scene()
else:
# Place any commands you want to run on import here.
print(f'Hello my name is {__name__=} because my module was imported by '
f'another module. ')
Demo Results:
If run directly from python
Hello my name is __name__='__main__' because my module was started by pyhton.
Traceback (most recent call last):
File "C:\Users\ctynd\OneDrive\CodeBase\StackOverflowActivity\OldScratches\scratch_2.py", line 27, in <module>
l = Level('brick', 5)
File "C:\Users\ctynd\OneDrive\CodeBase\StackOverflowActivity\OldScratches\scratch_2.py", line 9, in __init__
self.level = open(level)
OSError: [WinError 6] The handle is invalid
If imported:
import scratch_2
Results
Hello my name is __name__='scratch_2' because my module was imported by another module.

Related

Importing a class by referring to it with a variable?

Edit: This question was on the assumption that I could import parts of modules without importing the whole module. It turns out that isn't the case so I decided to just import the whole module with from ex45_extras import * anyway. That makes this question pointless, but I decided to not delete this question so that some other beginner with the same question can come here and find out the sad truth: You can't import modules as parts anyways
The following is the original question:
I'm a beginner so sry for the noob question. I want to call specific classes from a module with a variable. I don't want to call the whole module. And I need to do this using this class Nav() to control which classes are being imported. Is there a way to do this? Or is there a better solution?
class Nav():
def __init__(self):
print("This is class Nav")
def play(self):
current_scene_name = "A()" # this is where the variable is defined
from ex45_extras import current_scene_name # <- this is the one
x = Nav()
x.play()
Currently it's raising this error:
This is class Nav
Traceback (most recent call last):
File "D:\Programming\Python\LPTHW_Exs\ex45\test.py", line 11, in <module>
x.play()
File "D:\Programming\Python\LPTHW_Exs\ex45\test.py", line 7, in play
from ex45_extras import current_scene_name
ImportError: cannot import name 'current_scene_name' from 'ex45_extras' (D:\Programming\Python\LPTHW_Exs\ex45\ex45_extras.py)
Class names don't have a trailing () suffix — that's how you create an instance of one (i.e. by calling it).
Anyhow, if ex45_extras.py defines a class named A:
class A:
pass
Then you could import the class via a string containing its name, and then create an instance of it as shown below:
class Nav():
def __init__(self):
print("This is class Nav")
def play(self):
import ex45_extras
current_scene_name = 'A' # this is where the variable is defined
class_ = getattr(ex45_extras, current_scene_name) # Get class.
instance = class_() # Create instance of class.
print(f'{instance=}') # -> instance=<ex45_extras.A object at 0x010D4838>
x = Nav()
x.play()
guess it's because you're trying to import an string "A()" instead of a class A()

Script crashes when called from a second script

I have a report generation script (let's call this script A)that generates a PDF report. I want to import this in a new script (script B) and call the functions from within this new script.
The problem:
Script A crashes when called from Script B exactly at the creation of a QPixmap object. Python console restarts.
Script A runs fine when it is run on its own, but if I try to call it from Command Prompt python.exe crashes.
The following is Script B. All it does is it imports Script A, creates an instance of a class defined in A, and uses that to call a method of that object.
import Script A as et
a = "sample"
mdbPath = "C:\\Python27\\test.mdb"
directory = "C:\\Python27"
ui = et.HawkAutomationScript()
ui.Main(mdbPath,directory,a)
Script A contains the definition of a class called HawkAutomationScript. This object contains two functions to note: one Main function and one function to generate the report. These are the imported modules:
from random import*
import sys
import os
import subprocess
import time
from datetime import datetime
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import QRect
from PyQt4.QtGui import QTextDocument, QPrinter, QApplication, QPainter
from string import Template
import shutil
import time
import pyodbc
This is the definition of the class and the Main function:
doc = QTextDocument()
myCursor = QtGui.QTextCursor(doc)
class HawkAutomationScript(object):
def Main(self,mdb,directory,name):
Ui_FormObject = HawkAutomationScript()
## Filling in the Report ##
Ui_FormObject.fnGenerateReport(directory,name)
def fnGenerateReport(self,directory,name):
now = datetime.now()
dateString = now.strftime("%d-%b-%Y") # For getting Current Date
dirPath = "C:\\"
ResultName = "SelfTest_Results"
testName = name+".pdf"
subDirPath = dirPath + name
if(os.path.isdir(dirPath)):
if(os.path.isdir(subDirPath)):
subDirPath = subDirPath + testName
else:
os.mkdir(subDirPath)
subDirPath = subDirPath + testName
else:
os.mkdir(dirPath)
os.mkdir(subDirPath)
subDirPath = subDirPath + testName
pixmap = QtGui.QPixmap(doc.size().width(), doc.size().height()) ################
printer = QPrinter()
printer.setOutputFileName(subDirPath)
printer.setOutputFormat(QPrinter.PdfFormat)
doc.print_(printer)
# Create a QPainter to draw our content
painter = QPainter(pixmap)
painter.begin( printer )
doc.drawContents(painter)
painter.end()
This is all the relevant code and it is runnable.
If I run script B, A crashes at the QPixmap line marked in the code. But if I copy the lines from B and run A on its own, the PDF report is generated. But if I run A on its own from Command Prompt python.exe crashes.
Any help would be really appreciated. Thank you!!

How can I resolve the 'TypeError: 'list' object is not callable' error in this threaded pyside code that seems to work fine in a similar case?

The full traceback for my error is:
> python zthreadtest_tjedit.py
None
Traceback (most recent call last):
File "zthreadtest_tjedit.py", line 17, in run self.function()
TypeError: 'list' object is not callable
I apologize that's this code is a bit system specific and probably won't serve as an executable example for most people. Hopefully the solution is simple enough for someone to see right off. If you're not running zfs with a currently imported zpool, but are on a *nix platform with the weir.zfs module installed, it will return an empty list with the non-threaded code enabled (see comments in code for toggling threading). With the threading module enabled, it throws the error as shown above.
Confusing to me is that the second snip of code from Jo Plaete (https://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/) runs without error, and I simply modified this code to my needs.
EDIT: This error-causing difference may be related to the list object used in my code and not hers, but I still need to make mine work.
My question is: how do I resolve my error such that my threaded module runs correctly?
This seems simple, but I'm absolutely stumped. So much so that this is the first question I've posted on any help forum ever! I hope I've asked my question properly and I appreciate any help.
My Code, from much larger pyside gui program:
import PySide, sys
from PySide import QtCore, QtGui
from PySide.QtCore import *
from PySide.QtGui import *
import re, subprocess, threading
from weir import zfs
class WorkerThread(QThread):
def __init__(self, function):
QThread.__init__(self)
self.function = function
def __del__(self):
self.wait()
def run(self):
self.function()
return
class MainZ(QMainWindow):
def __init__(self):
super(MainZ, self).__init__()
# print(self)
# imported_pools = self.get_imported() # No threading
imported_pools = self.thread_test() # Use threading module
print(imported_pools)
def thread_test(self):
self.threader = WorkerThread(self.get_imported())
self.threader.start()
def get_imported(self):
pool_string = subprocess.getoutput(
'zpool list |grep -v ^NAME.*SIZE.*ALLOC |grep -o ^[a-Z0-9]*')
imported_pools = re.split(r'\s *', pool_string)
return imported_pools
app = QApplication(sys.argv)
form = MainZ()
app.exec_()
Code I modeled from Jo Plaete that works for me without error:
import sys, time
from PySide import QtCore, QtGui
class GenericThread(QtCore.QThread):
def __init__(self, function, *args, **kwargs):
QtCore.QThread.__init__(self)
self.function = function
self.args = args
self.kwargs = kwargs
def __del__(self):
self.wait()
def run(self):
self.function(*self.args,**self.kwargs)
return
class MyApp(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 280, 600)
self.setWindowTitle('threads')
self.layout = QtGui.QVBoxLayout(self)
self.testButton = QtGui.QPushButton("test")
self.connect(self.testButton, QtCore.SIGNAL("released()"), self.test)
self.listwidget = QtGui.QListWidget(self)
self.layout.addWidget(self.testButton)
self.layout.addWidget(self.listwidget)
def add(self, text):
""" Add item to list widget """
print("Add: " + text)
self.listwidget.addItem(text)
self.listwidget.sortItems()
def addBatch(self,text="test",iters= 5,delay=0.2):
""" Add several items to list widget """
for i in range(iters):
time.sleep(delay) # artificial time delay
self.add(text+" "+str(i))
def test(self):
self.listwidget.clear()
self.genericThread = GenericThread(
self.addBatch,"from generic thread ",delay=0.3)
self.genericThread.start()
# run
app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
app.exec_()
The
self.threader = WorkerThread(self.get_imported())
should read
self.threader = WorkerThread(self.get_imported)
When creating the thread, you want to pass the function itself and not the result of calling the function (which is a list).

Global name error when importing class as wild card Python

I am trying to make a multiple "page" GUI using tkinter and couldn't really find a good method. I resorted to using grid_forget and seperating the "pages" in methods and it works like a charm. However I am trying to seperate the methods into a seperate file to make everything a little cleaner but I keep getting a global name error upon trying to run one of the methods with all of the widgets from my main file/class.
Traceback (most recent call last):
File "C:/Users/Derek/PycharmProjects/whites/Main.py", line 3, in <module>
from screens import *
File "C:\Users\Derek\PycharmProjects\whites\screens.py", line 4, in <module>
import Main
File "C:\Users\Derek\PycharmProjects\whites\Main.py", line 54, in <module>
app = Application(master=main, w=main.winfo_width(), h=main.winfo_height())
File "C:\Users\Derek\PycharmProjects\whites\Main.py", line 20, in __init__
home_screen(self,True)
NameError: global name 'home_screen' is not defined
I also tried importing it such as import screens and tried to run screens.home_screen(self,True) and that yeilds
AttributeError: 'module' object has no attribute 'home_screen'
Even though it does
Example Main.py
from screens import *
import globals
class Application(tk.Frame):
globals.init()
def __init__(self, w, h, master=None):
tk.Frame.__init__(self, master)
self.grid()
self.window_width = w
self.window_height = h
home_screen(self,True)
query_screen(False)
res_screen(False)
settings_screen(False)
screens.py
import tkinter as tk
import globals
import Main
def home_screen(self, state):
*define widgets for this "screen"
[EDIT]
Here is a copy of the full files.screens , Main , globals
[EDIT: 2]
So I changed the code around to try a different solution and it basically the same error. module object has no attribute if I attempt to convert the screens.py into a class and initialize it as an object but nothing. So I am guessing this means it is not python at all and more my project settings have somewhere gone askew
You define:
def home_screen(self, state):
but it's not in any class!
Remove the self from the function signature and call it using only state variable only
EDIT:
If you create main.py:
from screens import *
class Application():
def __init__(self):
home_screen(True)
# then later on
a = Application() # this will print 'True'
and in file screens.py:
def home_screen(state):
print state
it will work (assuming both are in the same directory).
The solutions was to run the screens.py and not the main.py. Why that is I have no idea but it still ultimately fits my goal. If anyone would like to weigh in go for it.
[EDIT]
Final solution, change the way the program starts.It now runs just fine.
if __name__ == "__main__":
main = tk.Tk()
main.wm_title("White's Canoe Livery")
main.state("zoomed")
main.update()
# print(main.winfo_width())
app = Application(master=main, w=main.winfo_width(), h=main.winfo_height())
app.mainloop()

Using a dynamically loaded function as a target with multiprocessing.Pool

I am working on a GUI that needs to do some heavy computation in the background and then update the GUI when the calculation is complete. The multiprocessing module seems to be a good solution since I can use the *apply_async* method to specify the target and callback function. The callback function is used to update the GUI with the result. However I am having difficulty when trying to combine multiprocessing with a dynamically loaded module as in the following code. The error message is ImportError: No module named calc.
Is the error due to the fact that multiprocessing just doesn't work with dynamically loaded modules? If not, are there any ideas on a better approach?
from PySide.QtCore import *
from PySide.QtGui import *
import multiprocessing
import time
import sys
import os
import logging
import imp
PluginFolder = "plugins"
plugins = {}
def f(x):
y = x*x
time.sleep(2) #Simulate processing time.
return y
def load_plugin(name):
'''Load the python module 'name'
'''
location = os.path.join('.', PluginFolder)
info = imp.find_module(name, [location])
plugin = {"name": name, "info": info}
plugins[name] = imp.load_module(name, *plugin["info"])
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.pool = multiprocessing.Pool()
load_plugin('calc') #load ./plugins/calc.py
button1 = QPushButton('Calculate', self)
button1.clicked.connect(self.calculate)
button2 = QPushButton('Test', self)
button2.clicked.connect(self.run_test)
self.text = QTextEdit()
vbox1 = QVBoxLayout()
vbox1.addWidget(button1)
vbox1.addWidget(button2)
vbox1.addWidget(self.text)
myframe = QFrame()
myframe.setLayout(vbox1)
self.setCentralWidget(myframe)
self.show()
self.raise_()
def calculate(self):
#self.pool.apply_async(f, [10], callback=self.update_gui) #This works
#result = plugins['calc'].f(10) #this works
#self.update_gui(result)
self.pool.apply_async(plugins['calc'].f, [10], callback=self.update_gui) #This doesn't
def update_gui(self, result):
self.text.append('Calculation complete. Result = %d\n' % result)
def run_test(self):
self.text.append('Testing\n')
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = MainWindow()
app.exec_()
In ./plugins/calc.py, the function f is defined as in the above code.
This doesn't work since you're loading your calc module as a top-level module. Since no module calc is present in your sys.path or in current directory, it can't be found by import statement. Replacing import statement with following will do the trick:
plugins[name] = imp.load_module('{}.{}'.format(PluginFolder, name),
*plugin["info"])
For a plugin.calc being importable, plugins has to be a python module, i.e. contain a __init__.py file.
Any import <module> statement in your plugins files, such as in plugins/calc.py, will lead to a warning,
RuntimeWarning: Parent module 'plugins' not found while handling absolute import import <module>
The reason is that import process looks if parent module contains <module>, and while inside calc.py, can't find parent plugins module. You can rid of the error explicetely specifying plugins module location with, for example import plugins statement in main code.

Categories

Resources