Global variable in pytest - python

In Pytest I'm trying to do following thing, where I need to save previous result and compare current/present result with previous for multiple iterations.
I've done as following ways:
#pytest.mark.parametrize("iterations",[1,2,3,4,5]) ------> for 5 iterations
#pytest.mark.parametrize("clsObj",[(1,2,3)],indirect = True) ---> here clsObj is the instance. (clsObj.currentVal, here clsObj gets instantiated for every iteration and it is instance of **class func1**)
presentVal = 0
assert clsObj.currentVal > presrntVal
clsObj.currentVal = presentVal
When I do as above every time I loop presentVal get's assign to 0 (expected since it is local variable). Instead above I tried to declare presentVal as global like,global presentVal and also I intialized presentVal above my test case but didn't turn well.
class func1():
def __init__(self):
pass
def currentVal(self):
cval = measure() ---------> function from where I get current values
return cval
Can someone suggest how declare global variable in pytest or other best way
Thanks in advance!

What you are looking for is called a "fixture". Have a look at the following example, it should solve your problem:
import pytest
#pytest.fixture(scope = 'module')
def global_data():
return {'presentVal': 0}
#pytest.mark.parametrize('iteration', range(1, 6))
def test_global_scope(global_data, iteration):
assert global_data['presentVal'] == iteration - 1
global_data['presentVal'] = iteration
assert global_data['presentVal'] == iteration
You can essentially share a fixture instance across tests. It's intended for more complicated stuff like a database access object, but it can be something trivial like a dictionary :)
Scope: sharing a fixture instance across tests in a class, module or session

Related

Calling a Variable from Another Function in Python

I have spent the past few hours reading around but I'm not really understanding what I am sure is a very basic concept: passing values (as variables) between different functions.
class BinSearch:
def __init__(self,length,leng,r,obj_function,middle):
self.length = length
self.leng = leng
self.r = r
self.obj_function = obj_function
self.middle = middle
self.objtobin(obj_function)
def BinarySearch(length,leng,r):
mid = np.arange(0,len(length),1)
middle = min(mid) + (max(mid)-min(mid))//2
L_size = []
L = length[middle]
L_size.append(L)
return L
def objtobin(self,obj_function):
# length,leng,middle = BinSearch.BinarySearch()
if (obj_function>=0.98):
return BinSearch.BinarySearch(self.length,min(leng),self.middle-1)
else:
return BinSearch.BinarySearch(self.length,self.middle+1,max(leng))
BinSearch.objtobin(obj_function=max(objectivelist))
When I run the above code, BinSearch.objtobin code gives "objtobin() missing 1 required positional argument: 'self'" What should I do for this error?
Thanks for help!
Firstly, thank you all for your help. But I do not understand how should I change this code
I have started modifying your code so that it would run without errors, but there are a few other mistakes in there as well, and I have not tried to make sense of all your parameters.
It would look something like this, but I will explain below.
# --- OP's attempt that fails ---
# BinSearch.objtobin(obj_function=max(objectivelist))
# -- -- -- -- -- -- -- -- -- -- --
# --- Using an instance ---
figure_this_out_yourself = 100
# this variable is a placeholder for any parameters I had to supply
myBinSearchInstance = BinSearch(
length = figure_this_out_yourself,
leng = [figure_this_out_yourself],
r = figure_this_out_yourself,
obj_function = figure_this_out_yourself,
middle = figure_this_out_yourself)
myBinSearchInstance.objtobin(obj_function = max(objectivelist))
There is one important concept to be grasped here: self.
Let us consider this simple example function here, which shall always output a number one larger than last time.
counter = 0
def our_function ():
global counter
counter = counter + 1
return counter
print(our_function())
It is okay as it is, but it uses a global variable to keep track of its state. Imagine using it for two different purposes at the same time. That would be chaos!
So instead, we package this inside a class.
# unfinished apprach
counter = 0
class OurClass:
# This is called a static method
def our_function ():
global counter
counter = counter + 1
return counter
print(our_function())
When we try to run this, we run into a problem.
NameError: name our_function is not defined
This happens because it is now accessible only within that class. So we need to call it as
print(OurClass.our_function())
That makes it okay to have functions with the same name around - as long as they are in different classes - but it does not solve our chaos for using our_function multiple times at once. What we want is basically to have two independent counter variables. This is where instances come into play: Of course we could manually create a second function that uses a second global variable, but that gets out of hand quickly when you use it more and more.
So let's move counter inside our class.
class OurClass:
counter = 0
def our_function ():
global counter
counter = counter + 1
return counter
You guessed it - now counter is no longer defined:
NameError: name counter is not defined
So let us pass the instance variable that we want to use into the function as a parameter. And then use that instance to get its counter:
class OurClass:
counter = 0
def our_function (the_instance):
the_instance.counter = the_instance.counter + 1
return the_instance.counter
myInstance = OurClass()
mySecondInstance = OurClass()
print(OurClass.our_function(myInstance))
print(OurClass.our_function(mySecondInstance))
And successfully, both print statements print 1!
But that is a bit annoying because this the_instance is something that is not like the other arguments. To make it distinct, python allows us to avoid the first parameter and instead provide it as the receiver. Both of these work:
print(myInstance.our_function())
print(OurClass.our_function(mySecondInstance))
Python uses a very strong convention for these parameters. Instead of the_instance, call it self. See Why is self only a convention?.
class OurClass:
counter = 0
def our_function (self):
self.counter = self.counter + 1
return self.counter
myInstance = OurClass()
mySecondInstance = OurClass()
print(myInstance.our_function())
print(mySecondInstance.our_function())
Now we're almost done! Just one thing left to understand: Where do the parameters of __init__() come from?
They are passed to __init__() from the line where we construct it. So let me demonstrate by adding a starting value for our counter:
class OurClass:
counter = 0
def __init__ (self, starting_value):
self.counter = starting_value
def our_function (self):
self.counter = self.counter + 1
return self.counter
myInstance = OurClass(5)
mySecondInstance = OurClass(10)
print(myInstance.our_function())
print(OurClass.our_function(mySecondInstance))
This prints 6 and 11.
But what do those comments mean with #staticmethod? For that, see Difference between staticmethod and classmethod and Do we really need #staticmethod decorator in python to declare static method
.
In short: You can annotate any method in a class with either #staticmethod or #classmethod.
#staticmethod means that it can be called like myInstance.foo() when OurClass.foo() does not take self as a parameter. Without that decorator, you could only call it as OurClass.foo() but not as myInstance.foo().
#classmethod means that it can be called like myInstance.foo() and it does not get myInstance as the first parameter, but instead the class of myInstance, which is OurClass. That allows you e.g. to define alternative constructors. Also, a class method is not inherited when you subclass it, so it won't be mistakenly called.
The comments are pointing out that you could also use a #staticmethod and avoid creating an instance. For that, you would have to not use any variables in the class itself - but you aren't using those for long anyways, so you could all pass them as parameter to the function.

Delay an evaluation / lazy evaluation in Python

I want to delay the evaluation of a call to a member function of an instance of a class until this instance actually exists.
Minimum working example:
class TestClass:
def __init__(self, variable_0):
self.__variable_0 = variable_0
def get_variable_0(self):
return self.__variable_0
delayed_evaluation_0 = test_class.get_variable_0() # What should I change here to delay the evaluation?
test_class = TestClass(3)
print(delayed_evaluation_0.__next__) # Here, 'delayed_evaluation_0' should be evaluated for the first time.
I tried using lambda, yield and generator parentheses () but I can't seem to get this simple example to work.
How do I solve this problem?
a simple lambda works. When called, the function will fetch test_class variable from the current scope, and if it finds it, that will work, like below:
delayed_evaluation_0 = lambda : test_class.get_variable_0()
test_class = TestClass(3)
print(delayed_evaluation_0())
prints 3

Python: How do I fix my code so that the append will add the argument to the list?

I am very new to python and I've been trying to do this code where i use a tkinter button command to run a function, it works but the append() is not executing, meaning it does not append to the list.
The list and the function containing the append is outside the class and is then classed within a class through the use of tkinter button command
I've tried putting the function inside the class, it works but the append is not adding into the list again.
This is the code I've made that is somewhat similar to real one
prices = []
f = True
class firstclass():
def __init__(self):
while f == True:
my_function()
f = False
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
print(sum(prices))
the sample of real code is in this link, please take this into consideration as well
python: Appending a value to a list outside the class, function with append also outside the class, but function is called within a class
I expected that it would print the appended value which is 70, but it still printed 0
A few issues you need to deal with. First assigning f=True outside the class won't change the value inside, so if you instantiated the class it would just throw an UnboundLocalError complaining that f isn't initialized. You can try this yourself by instantiating the class with
fc = firstclass()
Without instantiation, you have no hope of it giving you the value you want. It is printing zero because of the function secondclass, which has a print statement that is not contained within a method, so it prints the value sum(prices) which the class is declared. That value is from the original declared value of prices which is []. At least that is the way you have shown it in your question. I'm not sure whether you meant to indent the print statement, which would mean it is part of secondclass. However, if you didn't indent you would get the same result as you haven't instantiated firstclass.
To correct this, see below. This code will output 70 as you intended.
prices = []
class firstclass():
def __init__(self):
my_function()
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
print('before instantiation', sum(prices))
fc = firstclass()
print('after instantiation', sum(prices))
fc is now an object of type firstclass and the __init__ method has called my_function to append the value 70 to prices.
There are two reasons this is happening.
You never called firstclass to actually initialize the
constructor.
You are trying to assign False to the variable f
which does not belong to the scope of the class. If you still assign
it, it's considered local. And at the moment the interpreter
detects that you assigned it, the while loop does not have any local
reference of f since you did not define it under the constructor.
See this answer for more details.
Here is the completed code:
prices = []
class firstclass():
f = True
def __init__(self):
while self.f:
my_function()
self.f = False
def my_function():
prices.append(70)
class secondclass():
def __init__(self):
pass
firstclass()
print(sum(prices))

Unit testing objects in Python - Object is not over written in setup

I'm unit testing classes in Python using unittest. As I understand it, unittest calls the setUp function before each test so that the state of the unit test objects are the same and the order the test are executed wouldn't matter.
Now I have this class I'm testing...
#! usr/bin/python2
class SpamTest(object):
def __init__(self, numlist = []):
self.__numlist = numlist
#property
def numlist(self):
return self.__numlist
#numlist.setter
def numlist(self, numlist):
self.__numlist = numlist
def add_num(self, num):
self.__numlist.append(num)
def incr(self, delta):
self.numlist = map(lambda x: x + 1, self.numlist)
def __eq__(self, st2):
i = 0
limit = len(self.numlist)
if limit != len(st2.numlist):
return False
while i < limit:
if self.numlist[i] != st2.numlist[i]:
return False
i += 1
return True
with the following unit tests...
#! usr/bin/python2
from test import SpamTest
import unittest
class Spammer(unittest.TestCase):
def setUp(self):
self.st = SpamTest()
#self.st.numlist = [] <--TAKE NOTE OF ME!
self.st.add_num(1)
self.st.add_num(2)
self.st.add_num(3)
self.st.add_num(4)
def test_translate(self):
eggs = SpamTest([2, 3, 4, 5])
self.st.incr(1)
self.assertTrue(self.st.__eq__(eggs))
def test_set(self):
nl = [1, 4, 1, 5, 9]
self.st.numlist = nl
self.assertEqual(self.st.numlist, nl)
if __name__ == "__main__":
tests = unittest.TestLoader().loadTestsFromTestCase(Spammer)
unittest.TextTestRunner(verbosity = 2).run(tests)
This test fails for test_translate.
I can do two things to make the tests succeed:
(1) Uncomment the second line in the setUp function. Or,
(2) Change the names of the tests such that translate occurs first. I noticed that unittest executes tests in alphabetical order. Changing translate to, say, atranslate so that it executes first makes all tests succeed.
For (1), I can't imagine how this affects the tests since at the very first line of setUp, we create a new object for self.st . As for (2), my complaint is similar since, hey, on setUp I assign a new object to self.st so whatever I do to self.st in test_set shouldn't affect the outcome of test_translate.
So, what am I missing here?
Without studying the detais of your solution, you should read the Default Parameter Values in Python by Fredrik Lundh.
It is likely that it explains your problem with your empty list as a default argument. The reason is that the list is empty only for the first time unless you make it empty explicitly later. The initialy empty default list is the single instance of the list type that is reused when no explicit argument is passed.
It is good idea to read the above article to fix your thinking about the default arguments. The reasons are logical, but may be unexpected.
The generally recommended fix is to use None as the default value of the __init__ and set the empty list inside the body if the argument is not passed, like this:
class SpamTest(object):
def __init__(self, numlist=None):
if numlist is None:
numlist = [] # this is the new instance -- the empty list
self.__numlist = numlist
This is due to the way default parameters behave in Python when using Mutable objects like lists: Default Parameter Values in Python.
In the line:
def __init__(self, numlist = []):
The default parameter for numlist is only evaluated once so you only have one instance of the list which is shared across all instance of the SpamTest class.
So even though the test setUp is called for every test it never creates a fresh empty list, and your tests which work upon that list instance end up stepping on each others toes.
The fix is to have something like this instead, using a non-mutable object like None:
def __init__(self, numlist = None):
if numlist is None:
numlist = []
self.__numlist = numlist
The reason it works when setting the property is that you provide a brand new empty list there, replacing the list created in the constructor.

accessing a variable in if __name__ == "main"

I have a program that compares two classes in a series of tests.
The main program (called initial.py) assigns both values to a dictionary
import testcheck
values = {}
valueChange = False
if __name__ == "__main__":
values['valueOne'] = testcheck.assignValue() #see note 1
values['valueTwo'] = testcheck.assignValueTwo()
testcheck.checkValues() #see note 2
while valueChange is True :
values['valueTwo'] = testcheck.assignValueTwo()
testcheck.checkValues()
Note 1: both of these return the same class but with different values
Note 2: compares the two classes. after a series of tests, valueChange is set to True, and one value is to be deleted using this code
import initial
...
if initial.valueChange is True:
del initial.values['valueTwo']
...
This returns the error
del initial.values['valueTwo']
KeyError: 'valueTwo'
I thought it was because adding valueOne and valueTwo would be adding it in the local scope, but even with global values it doesn't fix it. How would I go about solving this?
This appears to be a design issue. You seem to be setting up circular imports, which should be avoided if possible. If what you are after is to share a global state across modules of your package, you might want to make use of storing the state within your testcheck module, and not in a global variable of your initial.py
testcheck.py
# module globals
_TEST_VALUES = {}
valueChanged = False
...
def getTestValue(name):
return _TEST_VALUES.get('name', None)
def assignValue():
# do stuff
result = 'foo'
_TEST_VALUES['valueOne'] = result
return result
def assignValueTwo():
# do stuff
result = 'bar'
_TEST_VALUES['valueOne'] = result
return result
...
initial.py
testcheck.assignValue()
testcheck.assignValueTwo()
testcheck.checkValues()
while testcheck.valueChange:
testcheck.assignValueTwo()
testcheck.checkValues()
otherModule.py
import testcheck
...
if testcheck.valueChange:
try:
del initial.values['valueTwo']
except KeyError:
pass
...
I have no idea where this whole thing is going in terms of real usage. But maybe this will give you an idea of where to start looking. There is no longer a circular import of other modules importing your intial.py entry point. You are storing all the globals within the testcheck module. This example is very quick and dirty. Its only to illustrate.
No module should ever try to be accessing data of another module which handles the data within an if __name__ == "__main__" block. Because now you are making the assumption that it will always be used as the entry point (never imported by something else) and you start putting restrictions on your code.

Categories