I have the following class in Python.
import os,ConfigParser
class WebPageTestConfigUtils:
def __init__(self, configParser=None, configFilePath=None):
self.configParser = ConfigParser.RawConfigParser()
self.configFilePath = (os.path.join(os.getcwd(),'webPageTestConfig.cfg'))
def initializeConfig(self):
configParser.read(configFilePath)
return configParser
def getConfigValue(self,key):
return configParser.get('WPTConfig', key)
def main():
webPageTestConfigUtils = WebPageTestConfigUtils()
webPageTestConfigUtils.initializeConfig()
webPageTestConfigUtils.getConfigValue('testStatus')
if __name__ =='__main__':
main()
Upon execution . This gives me the error.
NameError: global name 'configParser' is not defined.
Why is python not able to recognize the instance variable here.
~
~
You are defining
...
self.configParser = ConfigParser.RawConfigParser()
...
And accessing using
...
configParser.read(configFilePath)
...
You have to access as self.configParser.
That's expected. In your code, python will not be able to access class members without self. Here is the correct code:
def initializeConfig(self):
self.configParser.read(self.configFilePath)
return self.configParser
def getConfigValue(self,key):
return self.configParser.get('WPTConfig', key)
Related
I am writing unit test in pytest and getting error on assert_called_once_with.
I tired to use same way as been shown in the pytest documentation but seems I am missing something.
# Class which I am trying to mock. (./src/Trading.py)
class BaseTrade:
def __init__(self, name):
self.name = name
class Trade(BaseTrade):
def __init__ (self, name):
BaseTrade.__init__(self, name)
def get_balance(self, value):
# do calculation and return some value
# for demo purpose hard-coding it
return value * 10
#unit test (./unitest/test_test.py
import mock
import unittest
import sys
sys.path.append("../src")
import Trading
class TestTradeClass(unittest.TestCase):
#classmethod
def setUpClass(self):
self.expected_balance = 100
#classmethod
def tearDownClass(self):
pass
def test_trade(self):
with mock.patch.object(Trading.Trade, 'get_balance', new = lambda self, x: (x * 10) ) as mock_method:
obj = Trading.Trade("AAPL")
value = obj.get_balance(10)
assert value == 100
mock_method.assert_called_once_with(100)
Error on mock_method.assert_called_once_with(100)
AttributeError: 'function' object has no attribute 'assert_called_once_with'
I'm now of the belief you want side_effect. How is this? One file, assume test.py:
#!/usr/bin/env python
import unittest
import mock
class BaseTrade:
def __init__(self, name):
self.name = name
class Trade(BaseTrade):
def __init__(self, name):
BaseTrade.__init__(self, name)
def get_balance(self, value):
# do calculation and return some value
# for demo purpose hard-coding it
return value * 10
class TestTradeClass(unittest.TestCase):
#classmethod
def setUpClass(cls):
cls.expected_balance = 100
def test_trade(self):
# Without mock
obj = Trade("AAPL")
value = obj.get_balance(10)
assert value == 100
# With Trade.get_balance param patched
with mock.patch.object(
Trade, 'get_balance', side_effect=lambda value: value * 11
) as mock_method:
obj = Trade("AAPL")
value = obj.get_balance(10)
assert value == 110
mock_method.assert_called_once_with(10)
if __name__ == "__main__":
unittest.main()
chmod +x test.py
./test.py
Output:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Explanation:
Use side_effect instead of new
Combined to one file to make it easier
removing Trading.Trade
#classmethod to use cls and not self.
mock_method.assert_called_once_with(10), as side_effect cares about the value passed via obj.get_balance(10) and exists to alter the output.
Closer? If not can you clarify what you're trying to mock?
It's not easy to tell, but if Trading.Trade.get_method() is actually a vanilla function and not a method - you may need unittest.mock.create_autospec()
Are any of these of assistance?
'function' object has no attribute 'assert_called_once_with'
Python3 mock replace function with another function
It's not clear whaat Trading.Trade is.
If by chance, Trading is a class that has a self.trade = Trade(...) inside, your question would be substantially different. You'd need to get in deeper, patching Trade.get_method, then. You'd likely want to import Trade from the same module class Trading uses it (e.g. from .trading import Trading, Trade) - not from where Trade is declared from - then patch the Trade.get_method.
I have a BatchJob specification file (batch.spec) something like below:
python = <<EOF
def foo():
return f"foo: I am {self.name}"
def bar():
return f"bar: I am {self.name}"
EOF
<batch>
name p&l_calculator
exec echo %foo()%
</batch>
I am converting this file to a python dict by using https://github.com/etingof/apacheconfig
from apacheconfig import *
with make_loader() as loader:
config = loader.load('batch.spec')
# Print content of python dict
for key, value in config.items():
print(key, value)
# output from print statement above
# python
# def foo():
# return f"foo: I am {self.name}"
#
# def bar():
# return f"bar: I am {self.name}"
# batch {'name': 'p&l_calculator', 'exec': 'echo %foo()%'}
Now I am converting this python dict to a BatchJobSpec object like below:
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch.get("name")
self.exec = batch.get("exec")
batchjobspec = BatchJobSpec(config.get("python"), config.get("batch"))
If I print batchjobspec fields, then I will get something like below
print(batchjobspec.pythoncode)
print(batchjobspec.name)
print(batchjobspec.exec)
# Output from above print statements
# def foo():
# return f"foo: I am {self.name}"
#
# def bar():
# return f"bar: I am {self.name}"
# p&l_calculator
# echo %foo()%
Problem: I want the value of "batchjobspec.exec" to be interpolated when I try to access it, i.e. it should not be "echo %foo()%" but it should be "echo foo: I am p&l_calculator".
i.e. somehow in the getter of fields, I want to check if there is "% %" syntax. If yes, and if content inside "% %" contains a callable then I want to call that callable and append the value returned from callable to the value of the corresponding field. I guess I will have to make these callables available in the BatchJobSpec dict as well.
Comment: I have foo as well as bar. exec(str) will execute both
In your self.pythoncode you have definitons of functions like def foo():. Therefore exec doesn't execute but do define these functions in the local namespace. To execute these functions as a class methode, you have to create a attribute, referencing these local functions, in the class itself.
In this example, the function names are known beforhand
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch['name']
self._exec = ['for', 'bar']
self.exec()
To make self visible in the local namespace, define the locals_ dict.
exec the string self.pythoncode results in insert the reference to the functions into locals_. To use these local references, as a class methode and make it persistent, use self.__setattr__(....
def exec(self):
locals_ = {'self': self}
exec(self.pythoncode, locals_)
for attrib in self._exec:
print('__setattr__({})'.format(attrib))
self.__setattr__(attrib, locals_[attrib])
Usage: Different python format syntax, as i using python 3.5
python = """
def foo():
return 'foo: I am {name}'.format(name=self.name)
def bar():
return 'bar: I am {name}'.format(name=self.name)
"""
if __name__ == "__main__":
batchjobspec = BatchJobSpec(config.get("python"), config.get("batch"))
print('echo {}'.format(batchjobspec.foo()))
print('echo {}'.format(batchjobspec.bar()))
Output:
__setattr__(foo)
__setattr__(bar)
echo foo: I am p&l_calculator
echo bar: I am p&l_calculator
Question I want the value of "batchjobspec.exec" to be interpolated when I try to access it
library/functions - exec
object.__setattr__
Change your class BatchJobSpec to:
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch.get("name")
self._exec = batch.get("exec")
#property
def exec(self):
to_exec = 'foo'
self.__setattr__(to_exec, lambda : exec('print("Hello world")'))
self.foo()
return None
Here is my example.py file:
from myimport import *
def main():
myimport2 = myimport(10)
myimport2.myExample()
if __name__ == "__main__":
main()
And here is myimport.py file:
class myClass:
def __init__(self, number):
self.number = number
def myExample(self):
result = myExample2(self.number) - self.number
print(result)
def myExample2(num):
return num*num
When I run example.py file, i have the following error:
NameError: global name 'myExample2' is not defined
How can I fix that?
Here's a simple fix to your code.
from myimport import myClass #import the class you needed
def main():
myClassInstance = myClass(10) #Create an instance of that class
myClassInstance.myExample()
if __name__ == "__main__":
main()
And the myimport.py:
class myClass:
def __init__(self, number):
self.number = number
def myExample(self):
result = self.myExample2(self.number) - self.number
print(result)
def myExample2(self, num): #the instance object is always needed
#as the first argument in a class method
return num*num
I see two errors in you code:
You need to call myExample2 as self.myExample2(...)
You need to add self when defining myExample2: def myExample2(self, num): ...
First, I agree in with alKid's answer. This is really more a comment on the question than an answer, but I don't have the reputation to comment.
My comment:
The global name that causes the error is myImport not myExample2
Explanation:
The full error message generated by my Python 2.7 is:
Message File Name Line Position
Traceback
<module> C:\xxx\example.py 7
main C:\xxx\example.py 3
NameError: global name 'myimport' is not defined
I found this question when I was trying to track down an obscure "global name not defined" error in my own code. Because the error message in the question is incorrect, I ended up more confused. When I actually ran the code and saw the actual error, it all made sense.
I hope this prevents anyone finding this thread from having the same problem I did. If someone with more reputation than I wants to turn this into a comment or fix the question, please feel free.
You have to create an instance of the myClass class, and not the instance of the whole module(and i edit variables names to be less awful):
from myimport import *
def main():
#myobj = myimport.myClass(10)
# the next string is similar to above, you can do both ways
myobj = myClass(10)
myobj.myExample()
if __name__ == "__main__":
main()
While the other answers are correct, I wonder if there is really a need for myExample2() being a method. You could as well implement it standalone:
def myExample2(num):
return num*num
class myClass:
def __init__(self, number):
self.number = number
def myExample(self):
result = myExample2(self.number) - self.number
print(result)
Or, if you want to keep your namespace clean, implement it as a method, but as it doesn't need self, as a #staticmethod:
def myExample2(num):
return num*num
class myClass:
def __init__(self, number):
self.number = number
def myExample(self):
result = self.myExample2(self.number) - self.number
print(result)
#staticmethod
def myExample2(num):
return num*num
I have a model where I want to use a class method to set the default of for a property:
class Organisation(db.Model):
name=db.StringProperty()
code=db.StringProperty(default=generate_code())
#classmethod
def generate_code(cls):
import random
codeChars='ABCDEF0123456789'
while True: # Make sure code is unique
code=random.choice(codeChars)+random.choice(codeChars)+\
random.choice(codeChars)+random.choice(codeChars)
if not cls.all().filter('code = ',code).get(keys_only=True):
return code
But I get a NameError:
NameError: name 'generate_code' is not defined
How can I access generate_code()?
As I said in a comment, I would use a classmethod to act as a factory and always create you entity through there. It keeps things simpler and no nasty hooks to get the behaviour you want.
Here is a quick example.
class Organisation(db.Model):
name=db.StringProperty()
code=db.StringProperty()
#classmethod
def generate_code(cls):
import random
codeChars='ABCDEF0123456789'
while True: # Make sure code is unique
code=random.choice(codeChars)+random.choice(codeChars)+\
random.choice(codeChars)+random.choice(codeChars)
if not cls.all().filter('code = ',code).get(keys_only=True):
return code
#classmethod
def make_organisation(cls,*args,**kwargs):
new_org = cls(*args,**kwargs)
new_org.code = cls.generate_code()
return new_org
import random
class Test(object):
def __new__(cls):
cls.my_attr = cls.get_code()
return super(Test, cls).__new__(cls)
#classmethod
def get_code(cls):
return random.randrange(10)
t = Test()
print t.my_attr
You need specify the class name: Organisation.generate_code()
I have list of class names and want to create their instances dynamically. for example:
names=[
'foo.baa.a',
'foo.daa.c',
'foo.AA',
....
]
def save(cName, argument):
aa = create_instance(cName) # how to do it?
aa.save(argument)
save(random_from(names), arg)
How to dynamically create that instances in Python? thanks!
Assuming you have already imported the relevant classes using something like
from [app].models import *
all you will need to do is
klass = globals()["class_name"]
instance = klass()
This is often referred to as reflection or sometimes introspection. Check out a similar questions that have an answer for what you are trying to do:
Does Python Have An Equivalent to Java Class forname
Can You Use a String to Instantiate a Class in Python
This worked for me:
from importlib import import_module
class_str: str = 'A.B.YourClass'
try:
module_path, class_name = class_str.rsplit('.', 1)
module = import_module(module_path)
return getattr(module, class_name)
except (ImportError, AttributeError) as e:
raise ImportError(class_str)
You can often avoid the string processing part of this entirely.
import foo.baa
import foo.AA
import foo
classes = [ foo.baa.a, foo.daa.c, foo.AA ]
def save(theClass, argument):
aa = theClass()
aa.save(argument)
save(random.choice(classes), arg)
Note that we don't use a string representation of the name of the class.
In Python, you can just use the class itself.
You can use the python builtin eval() statement to instantiate your classes.
Like this:
aa = eval(cName)()
Notice!
using eval is dangerous and is a key for lots of security risks based on code injections.
My problem was that I wanted to pass arguments into __init__ with the arguments being specified in a string on the command line. For example, the equivalent of
import a.b.ClassB as ClassB
instance = ClassB.ClassB('World')
The string on the command line is "a.b.ClassB.ClassB('World')"
With the following class in module a.b.ClassB
class ClassB():
def __init__(self, name:str):
self._name = name
def hello(self):
print("Hello " + self._name + "!")
we can create this class with the following
import importlib
def create_instance(class_str:str):
"""
Create a class instance from a full path to a class constructor
:param class_str: module name plus '.' plus class name and optional parens with arguments for the class's
__init__() method. For example, "a.b.ClassB.ClassB('World')"
:return: an instance of the class specified.
"""
try:
if "(" in class_str:
full_class_name, args = class_name = class_str.rsplit('(', 1)
args = '(' + args
else:
full_class_name = class_str
args = ()
# Get the class object
module_path, _, class_name = full_class_name.rpartition('.')
mod = importlib.import_module(module_path)
klazz = getattr(mod, class_name)
# Alias the the class so its constructor can be called, see the following link.
# See https://www.programiz.com/python-programming/methods/built-in/eval
alias = class_name + "Alias"
instance = eval(alias + args, { alias: klazz})
return instance
except (ImportError, AttributeError) as e:
raise ImportError(class_str)
if __name__ == "__main__":
instance = create_instance("a.b.ClassB.ClassB('World')")
instance.hello()
Best Answer I found:
Better Way is to make a dictionary:
objects ={}
Names =[object1,object2, object3]
For objname in Names:
objects[objname]=classname()
Found in:
https://www.thecodingforums.com/threads/create-object-name-from-string-value.712461/