I need to make a script that calls every .py file in a specific directory. These are plugins to the main program. Each plugin script must be able to access classes and methods from the calling script.
So I have something like this:
mainfile.py:
class MainClass:
def __init__(self):
self.myVar = "a variable"
for f in os.listdir(path):
if f.endswith(".py"):
execfile(path+f)
def callMe(self):
print self.myVar
myMain = MainClass()
myMain.callMe()
And I want to be able to do the following in callee.py
myMain.callMe()
Just using import will not work because mainfile.py must be the program that is running, callee.py can be removed and mainfile will run on its own.
import os
class MainClass:
def __init__(self):
self.myVar = "a variable"
self.listOfLoadedModules = []
for f in os.listdir("."):
fileName, extension = os.path.splitext(f)
if extension == ".py":
self.listOfLoadedModules.append(__import__(fileName))
def callMe(self):
for currentModule in self.listOfLoadedModules:
currentModule.__dict__.get("callMe")(self)
myMain = MainClass()
myMain.callMe()
With this code you should be able to call callMe function of any python file in the current directory. And that function will have access to MainClass, as we are passing it as a parameter to callMe.
Note: If you call callMe of MainClass inside callee.py's callMe, that will create infinite recursion and you will get
RuntimeError: maximum recursion depth exceeded
So, I hope you know what you are doing.
Related
I have a basic.py file under a specific folder which defined a class:
class test_function:
def loop_unit(self,str):
global test_list
test_list.append(str)
I have another main.py which have following code
from folder import basic
test_list=[]
object=basic.test_function()
object.loop_unit('teststr')
print(test_list)
it will give an error says
name 'test_list' is not defined(it trackback to test_list.append(str) )
I actually defined global variable in the function, and I defined it at the start of the main code, why it still said this is not defined?
You defined main.test_list; test_function.loop_unit wants basic.test_list.
from folder import basic
basic.test_list = []
object = basic.test_function()
object.loop_unit('teststr')
print(basic.test_list)
Try to do this in your class definition:
class test_function:
def __init__(self):
self.test_list = []
def loop_unit(self,str):
sel.test_list.append(str)
from folder import basic
#test_list=[] --remove this line
object=basic.test_function()
object.loop_unit('teststr')
#print(test_list) ---remove this line but add this:
print(object.test_list)
Try and tell me if it works.
I am writing Python code (based on PyQt5 signals and slots). I need to make my code "Scriptable". By scriptable I mean the user can utilize the internal objects himself in a user-defined python script to develop/automate some functions,..etc. But I have no idea of how to implement it clearly.
I have tried using (exec) function in python in the following way:
user-def.py
def script_entry(main_object_in_my_code):
# Connecting signal from main_object_in_my_code (inherited from QObject) to other functions in this
# file. example:
main_object_in_my_code.event_1.connect(function_1)
#QtCore.pyqtSlot(str)
def function_1 (args):
#do user-defined logic using those args.
then in my script when user want to execute it, he inputs (as example)
source user-def.py
the main script reads the script and uses exec as the following:
with open(script_path) as f:
script = f.read()
exec(script, globals())
the problem is that events are triggered but function function_1 is not executed.
I am sure this is not the right way to do this. So, How can I implement my code to be (scriptable) using user defined scripts?
I would recomend to create a class and extend from it, let the 'user' call the functions when s/he needs.
If you are not in touch with class inheritance check this tutorial
source_def.py
class Main:
def __init__(self):
super(Main, self).__init__()
def script_entry(self, main_object_in_my_code):
main_object_in_my_code.event_1.connect( function_1 )
#QtCore.pyqtSlot(str)
def function_1( self, args ):
#this checks if the function is set
invert_op = getattr(self, "user_function", None)
if callable(user_function):
eval('self.user_function( args )')
user_def.py
from source_def import Main
class UserClass( Main ):
def __init__(self):
super(UserClass, self).__init__()
def user_function(self , args ):
print( args )
Try this
Framework: Robot, Language: Python-3.7.1 Proficiency: Novice
I have a variable args=[] defined at class level. The values of the variables are being assigned from command prompt using module 'sys'
import sys
class Runner():
args = []
def argument_reader(self):
self.args = list(sys.argv)
def login(self):
return self.args[1], self.args[2]
I could print all the values of args as long as execution stays within the module. If I wanted to call the same values from other module, it does not return anything as the values are being cleared out from the memory. Since class variables are static by default in python, why system is not RETAINING the values?
cmd line>>py Runner.py testing test#123
For Example:
Calling method from same class:-
run = Runner()
run.argument_reader()
print(run.login())
Output>>> testing, testing#123
Calling the same method from another class:-
runn = Runner.Runner()
print(runn.login())
output>> IndexError: list index out of range
If you want a singleton-type value, change your code to look like this.
class Runner():
args = []
def argument_reader(self):
Runner.args = list(sys.argv)
def login(self):
return Runner.args[1], Runner.args[2]
Otherwise, you'll have to call argument_reader() on each instance.
I am trying to organize my program better, and have decided to have small files that are imported into final.py.
Here I want DIrectorySetup to be initiated at the beginning of main. I want to be able to then call the directories.
This is what I tried:
class DirectorySetup:
'''The directory paths for the program'''
def __init__(self):
self.cwd = os.getcwd()
self.Raw_data_dir= self.cwd + '\Raw_data'
self.Clean_data_dir= self.cwd + '\Clean_data'
self.table_dir= self.cwd + '\Tables'
def main(): # Define the main function
#the class with the directory
Directory= DirectorySetup()
os.chdir(Directory.table_dir)
###does other things that I removed for clarity ###
if __name__ == "__main__":
main()
And then I run it in my final.py program:
import INIT_SCTFT
import os
first=INIT_SCTFT
first.main()
first.DirectorySetup.Clean_data_dir
That gives me the error
first.DirectorySetup.Clean_data_dir
AttributeError: type object 'DirectorySetup' has no attribute 'Clean_data_dir'
How do I get main() to save DirectorySetup?
Notice:
You are importing module INIT_SCTFT and then assign first to this module.
Now first is a module (you can check by printing type(first).
first.main() will execute main function from INIT_SCTFT. All main is doing is creating an object and changing current dir. Then it ends.
Then first.DirectorySetup.Clean_data_dir try to call Clean_data_dir from class DirectorySetup. But class DirectorySetup does not have defined Clean_data_dir! An object of class DirectorySetup has this attribute. So if you want to get access to this attribute, you have to create an object first.
For example:
obj = first.DirectorySetup()
obj.Clean_data_dir
EDIT:
To answer your question from comment. It depends on what you want to achieve. For exapmle, you can create some method that will return a list of objects.
class DirectorySetup:
'''The directory paths for the program'''
def __init__(self):
self.cwd = os.getcwd()
self.Raw_data_dir= self.cwd + '\Raw_data'
self.Clean_data_dir= self.cwd + '\Clean_data'
self.table_dir= self.cwd + '\Tables'
def create_objects():
one = DirectorySetup()
two = DirectorySetup()
three = DirectorySetup()
return one, two, three
Then in final.py you can create list of objects: objects = first.create_objects()
Or as you mentioned you can wrap it into some class:
class my_objects:
one = DirectorySetup()
two = DirectorySetup()
three = DirectorySetup()
Then in final.py you access it by: first.my_objects.one.
Also notice that if you decide to put objects in init:
class my_objects:
def __init__():
one = DirectorySetup()
two = DirectorySetup()
three = DirectorySetup()
Then first you will need to create an object of this class to get access to those variables obj = first.my_objects() then you can use it: obj.one.
Your problem is that python is garbage collecting your DirectorySetup instance after the function main has been called.
The simplest solution would be to have main just return the reference of the DirectorySetup instance so you can then access it:
def main(): # Define the main function
#the class with the directory
Directory= DirectorySetup()
os.chdir(Directory.table_dir)
return Directory
###does other things that I removed for clarity ###
You would then just change your final.py script to:
import INIT_SCTFT
import os
first=INIT_SCTFT
directory = first.main()
directory.Clean_data_dir
How about you do it out of main?
DirectoryFile.py
class DirectorySetup:
'''The directory paths for the program'''
def __init__(self):
self.cwd = os.getcwd()
self.Raw_data_dir= self.cwd + '\Raw_data'
self.Clean_data_dir= self.cwd + '\Clean_data'
self.table_dir= self.cwd + '\Tables'
#the class with the directory
Directory= DirectorySetup()
os.chdir(Directory.table_dir)
and then access Directory object from final.py
from DirectoryFile import Directory
#access variable Directory's member
print(Directory.Clean_data_dir)
The attribute only gets added into the object when init() is called which happens when an object is instantiated.
EDIT: On second thoughts, you could create a global variable out of main() which could go like this:
Directory = None
def main():
global Directory
Directory= DirectorySetup()
and then access it from final.py
Μy Mainclass creates a simple QmainWindows like this:
class mcManageUiC(QtGui.QMainWindow):
def __init__(self):
super(mcManageUiC, self).__init__()
self.initUI()
def initUI(self):
self.show()
And at the end of my file I launch it like this:
def main():
app = QtGui.QApplication(sys.argv)
renderManagerVar = mcManageUiC()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
My problem is that each time i source it, it launches a new window.
I would like to know if there is a way to detect existence of previous class instance in my script (so that I close the old one or avoid launching a new one), or any other solutions?
Also, when compiling my code with py2exe, same problem with my .exe file on Windows; it launchs a new window every time. Could i add something in the setup.py for Windows to not act like this?
Is it possible, if yes then how?
Note: I'm using Windows 7 64bit compiling with eclipse.
There are a couple ways to do this, you can use a Class attribute to store all the instances -- If you do it this way, you may want to store them as weak references via the weakref module to prevent issues with garbage collecting:
class MyClass(object):
_instances=[]
def __init__(self):
if(len(self._instances) > 2):
self._instances.pop(0).kill() #kill the oldest instance
self._instances.append(self)
def kill(self):
pass #Do something to kill the instance
This is a little ugly though. You might also want to consider using some sort of Factory which (conditionally) creates a new instance. This method is a little more general.
import weakref
class Factory(object):
def __init__(self,cls,nallowed):
self.product_class=cls #What class this Factory produces
self.nallowed=nallowed #Number of instances allowed
self.products=[]
def __call__(self,*args,**kwargs):
self.products=[x for x in self.products if x() is not None] #filter out dead objects
if(len(self.products) <= self.nallowed):
newproduct=self.product_class(*args,**kwargs)
self.products.append(weakref.ref(newproduct))
return newproduct
else:
return None
#This factory will create up to 2 instances of MyClass
#and refuse to create more until at least one of those
#instances have died.
factory=Factory(MyClass,2)
i1=factory("foo","bar") #instance of MyClass
i2=factory("bar","baz") #instance of MyClass
i3=factory("baz","chicken") #None
You can limit the number of instances you want to create in your code just by adding a counter:
class A(object):
ins = 0 # This is a static counter
def __init__(self):
if A.ins >= 1: # Check if the number of instances present are more than one.
del self
print "Failed to create another instance" #if > 1, del self and return.
return
A.ins += 1
print "Success",str(self)
Try running via:
lst = []
for i in range(1,101):
a=A()
lst.append(a)
you could monopolize a socket
import socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
"Network Error!"
s.settimeout(30)
try:
s.connect(('localhost' , 123))
except:
"could not open...already in use socket(program already running?)"
no idea if this is a good method but I have used it in the past and it solves this problem
this was designed to prevent launching a program when it was already running not from launching a new window from within a single script that is spawning several windows...
Use a class variable:
class mcManageUiC(QtGui.QMainWindow):
singleton = None
def __init__(self):
if not mcManageUiC.singleton: #if no instance yet
super(mcManageUiC, self).__init__()
self.initUI()
...
mcManageUiC.singleton = self
else:
...
def initUI(self):
self.show()