It my first try to realize a "little bit bigger" project in python. Thus I want to structure the whole project using different python files. I also need some global variables. The following example works, if I put everything in one file. As soon as I split in two files it doesn't work anymore. What's an elegant way to solve the problem:
class MyClass:
def call(self):
print("In Methode call")
self.check()
def check(self):
global a
if a:
print("a ist True")
a = False
else:
print("a ist False")
a = True
def methode3(self):
print("In methode 3")
if __name__=="__main__":
a=True
instanz = MyClass()
instanz.methode3()
instanz.call()
instanz.check()
This script itself works fine.
If I call it now from the following second script, I get the error that 'a'is not defined. Call of instanz.methode3() works of course.
import test
a = True;
instanz = test.MyClass();
instanz.methode3()
instanz.call()
The following check,
if __name__=="__main__":
Is only called from when the file is run by itself as opposed to being imported. Declaring the a outside this if should work as intended.
Also, to access the new variable a, use test.a.
Related
I am new to learn pytest. In bellow sample code.
how can i get A() object in test_one function when fixture is in autouse mode?
import pytest
import time
class A:
def __init__(self):
self.abc = 12
#pytest.fixture(autouse=True)
def test_foo():
print('connecting')
yield A()
print('disconnect')
def test_one():
#how can i get A() object?
print([locals()])
assert 1 == 1
You can always add the fixture as parameter despite the autouse:
def test_one(test_foo):
print(test_foo)
assert 1 == 1
If you don't want to use the fixture parameter for some reason, you have to save the object elsewhere to be able to access it from your test :
a = None
#pytest.fixture(autouse=True)
def test_foo():
global a
a = A()
yield
a = None
def test_one():
print(a)
assert 1 == 1
This could be made a little better if using a test class and put a in a class variable to avoid the use of the global var, but the first variant is still the preferred one, as it localizes the definition of the object.
Apart from that, there is no real point in yielding an object you don't have access to. You may consider if autouse is the right option for your use case. Autouse is often used for stateless setup / teardown.
If your use case is to do some setup/teardown regardless (as suggested by the connect/disconnect comments), and give optional access to an object, this is ok, of course.
I have a class where I want to call different modules form it, depending on an input from the user.
In my mind it would look something like this:
class Test:
def test1:
print("Hello world")
def test2:
print("farewell world")
user = input("> ")
Test.f{user}
Where it now will call what the user has told it to, but it doesn't work.
So my question is if it's possible, if it is then how I would accomplish it.
When trying examples from the given link, I keep encountering a problem for example where it tells me
"TypeError: test1() takes 0 positional arguments but 1 was given"
when the input looks like so:
getattr(globals()['Test'](), 'test')()
this is not the only one, and all I have tried leads to problems.
leading me to believe that either my problem is different, or I'm implementing it wrong.
Help with either scenario is much a appreciate.
You should try using getattr().
for example:
class Test:
def test1():
print("Hello world")
def test2():
print("farewell world")
userinput = input('Which function do you wish to call?\n')
# getattr() takes 2 parameters, class name, and attribute name.
myfunc = getattr(Test, userinput)
myfunc()
I want to access the calling environment from an imported module.
import child
…
def test(xxx):
print("This is test " + str(xxx))
child.main()
…
now on child:
import inspect
def main():
caller = inspect.currentframe().f_back
caller.f_globals['test']("This is my test")
This works, but it's not fancy. Is there a simplification like 'self' when use in a class? the idea is to do: caller.test('abc') instead.
One option to pass the caller as a parameter like: child.main(self), however self is not available in this context.
Python only load one version of a module so, tempted with this idea:
import sys
myself=sys.modules[__name__]
a then sending myself to the child:
…
child.main(myself)
…
Creates a reference to (a new) module, but not the running one, this is like creating a new class: one code buy a different environment.
If you already have a way of accessing the correct functions and data that works, why not just store f_globals on an instance of a wrapper class and then call things from the instance as if they were unbound properties? You could use the class itself, but using an instance ensures that the data you get from the imported file are valid when you create the object. Then you can access using the dot operator the way you want. This is your child file:
import inspect
class ImportFile:
def __init__(self, members):
self.__dict__.update(members)
def main():
caller = inspect.currentframe().f_back
imported_file = ImportFile(caller.f_globals)
imported_file.test("This is my test")
Outputs:
This is test This is my test
Admittedly, I don't have your setup, importantly the module you're trying to pull from, so it's hard to confirm whether or not this will work for you even though it has for me, but I think you could also use your method of calling main with globals() or even inspect.getmembers() since while inside the module you're importing you're still on the frame you're accessing with f_back from inside child.
The imported module:
import child
def test(xxx):
print("This is test " + str(xxx))
child.main(globals())
Child:
import inspect
class ImportFile:
def __init__(self, members):
self.__dict__.update(members)
def main(caller):
imported_file = ImportFile(caller)
imported_file.test("This is my test")
Outputs:
This is test This is my test
I have a class that contains a number of methods:
class PersonalDetails(ManagedObjectABC):
def __init__(self, personal_details):
self.personal_details = personal_details
def set_gender(self):
self.gender='Male:
def set_age(self):
self.set_age=22
etc.
I have many such methods, all that begin with the word `set. I want to create a new method within this class that will execute all methods that begin with set, like this:
def execute_all_settings(self):
'''
wrapper for setting all variables that start with set.
Will skip anything not matching regex '^set'
'''
to_execute=[f'''self.{i}()''' for i in dir(self) if re.search('^set',i)
print(to_execute)
[exec(i) for i in to_execute]
However, this reports an error:
NameError: name 'self' is not defined
How can I go about doing this?
more info
The reason I want to do it this way, rather than simply call each method individually, is that new methods may be added in the future, so I want to execute all methods (that start with "set" no matter what they are)
Do not use either exec or eval. Instead use getattr.
Also note that set_age is both a method and an attribute, try to avoid that.
import re
class PersonalDetails:
def __init__(self, personal_details):
self.personal_details = personal_details
def set_gender(self):
self.gender = 'Male'
def set_age(self):
self.age = 22
def execute_all_settings(self):
'''
wrapper for setting all variables that start with set.
Will skip anything not matching regex '^set'
'''
to_execute = [i for i in dir(self) if re.search('^set', i)]
print(to_execute)
for func_name in to_execute:
getattr(self, func_name)()
pd = PersonalDetails('')
pd.execute_all_settings()
print(pd.gender)
# ['set_age', 'set_gender']
# Male
This solution will work as long as all the "set" methods either do not expect any arguments (which is the current use-case), or they all expect the same arguments.
I had generated a few values and had populated them into a spreadsheet using xlsxwriter. This is how I did it:
class main1():
.
.
.
.
def fun1():
workbook = xlsxwriter.Workbook(self.Output_fold+'Test'+time.strftime("%H_%M_%S_%d_%m_%Y")+'.xlsx')
worksheet_A = workbook.add_worksheet('Sheet_A')
.
.
worksheet_A.write(row,col,<val>)
.
.
workbook.close()
Now, since I had to make multiple writes, and added more complex logic, I decided to have another function introduced fun2 which would write the values accordingly. The new logic requires generating values in fun1 as well as fun2 (by calling another function fun3). So, I decided to replace variables workbook etc with self.workbook and likewise. My modified script looks like this :
main_file.py
import xlsxwriter
import libex
import os
import time
import sys
import string
class main_cls():
def __init__(self):
self.i=0
self.t1=""
self.t2=""
pwd=os.getcwd().split('\\')
base='\\'.join(pwd[0:len(pwd)-1])+'\\'
print base
self.Output_fold=base+"Output\\"
self.Input_fold=base+"Input\\"
self.workbook=xlsxwriter.Workbook(self.Output_fold+'Test_'+time.strftime("%H_%M_%S_%d_%m_%Y")+'.xlsx')
self.worksheet_A = self.workbook.add_worksheet('Sheet_A')
self.worksheet_A.write(self.i,self.i,"Text 1")
self.worksheet_A.write(self.i,self.i+1,"Text 2")
self.i+=1
def fun1(self):
self.t1="1"
self.t2="2"
self.worksheet_A.write(self.i,self.i,self.t1)
self.worksheet_A.write(self.i,self.i+1,self.t2)
self.i+=1
self.eg=libex.exlib()
self.t1=self.eg.gen(0)
self.t2=self.eg.gen(0)
self.fun2()
self.workbook.close()
def fun2(self):
if option==1:
self.fun3()
def fun3(self):
self.t1=self.eg.gen(0)
self.t2=self.eg.gen(1)
self.worksheet_A.write(self.i,self.i,self.t1)
self.worksheet_A.write(self.i,self.i+1,self.t2)
self.i+=1
option=int(sys.argv[1])
if len(sys.argv)==2:
p=main_cls()
if option==1:
p.fun1()
else:
pass
else:
print "Wrong command"
libex.py
class exlib():
def __init__(self):
self.a="duh"
def gen(self,x):
if int(x)==0:
return(self.a)
elif int(x)==1:
self.a=str(self.a+" "+self.a+" "+self.a+" !!!")
return(self.a)
Now, this works in this particular case but in the actual code, it doesn't. The file itself is not getting created in the output directory. Then, I added the following line:
print "Workbook created at path : ",self.workbook.filename
to see if the file is getting created and it surprisingly showed with full path!!!
Where could I be going wrong here and how can I get this fixed?
UPDATE1: I played around a bit with it and found that removing self from self.workbook moving workbook to __init__(self) creates the file with the initial values populated.
UPDATE2: Have replicated my code in a minimal way as suggested. And this one works pretty well!!!
Tried to reproduce, file is being created just fine, maybe you have a problem with the self.Output_fold variable, or with file permissions or with your code editor's file explorer.