I'm relatively new to python, and I'm trying to figure out an issue, where I'm trying to write a generalised function.
In this scenario, I have a settings_file.py file alongside my app.py program. The settings_file.py is optional.
Content of settings_file.py:
myvariable = "foo"
Earlier in my program I (optionally) import the settings file:
try:
import settings_file
except ImportError:
pass
native version:
if settings_file.myvariable:
print "myvariable found from settings_file!"
return settings_file.myvariable
What I'm trying to do:
element_name = "myvariable"
if settings_file.eval(element_name):
print "{} found from settings_file!".format(element_name)
return settings_file.element_name
I think what I'm struggling with, is the if statement line, more spefically, the settings_file.eval(element_name) part.
I'm quite new to this, and my understanding is python should resolve the element_name back to a string for me. Maybe I have not typeset correctly.
I cant get it to resolve the variable name.
Edit: Perhaps I've not been clear, or misleading. I'm trying to return the value in the settings file back from a generalised function that I'm writing this element within. My desired outcome is that "foo" will be returned, which is the value of variable "myvariable" in settings_file.py.
Edit2: I think I worked out something based on response from #9769953
if getattr(settings_file, element_name, None):
print "{} found from settings_file!".format(element_name)
return getattr(settings_file, element_name, None)
If you're evaluating variable names, or otherwise want flexible variable names, 9 out of 10 times, you should use dicts.
Here, there is (even) more going on: you should first check that settings_file actually exist, before trying to get an attribute. Then, you could use getattr(settings_file, element_name):
try:
import settings_file
except ImportError:
settings_file = None
...
element_name = "myvariable"
return getattr(settings_file, element_name, None)
which returns None in case "myvariable" was not found, or the import failed. It doesn't explicitly test for settings_file not to be None, since getattr() will then just return None whatever the value of element_name.
Related
I have a class with some #staticmethod's that are procedures, thus they do not return anything / their return type is None.
If they fail during their execution, they throw an Exception.
I want to unittest this class, but I am struggling with designing positive tests.
For negative tests this task is easy:
assertRaises(ValueError, my_static_method(*args))
assertRaises(MyCustomException, my_static_method(*args))
...but how do I create positive tests? Should I redesign my procedures to always return True after execution, so that I can use assertTrue on them?
Without seeing the actual code it is hard to guess, however I will make some assumptions:
The logic in the static methods is deterministic.
After doing some calculation on the input value there is a result
and some operation is done with this result.
python3.4 (mock has evolved and moved over the last few versions)
In order to test code one has to check that at least in the end it produces the expected results. If there is no return value then the result is usually stored or send somewhere. In this case we can check that the method that stores or sends the result is called with the expected arguments.
This can be done with the tools available in the mock package that has become part of the unittest package.
e.g. the following static method in my_package/my_module.py:
import uuid
class MyClass:
#staticmethod
def my_procedure(value):
if isinstance(value, str):
prefix = 'string'
else:
prefix = 'other'
with open('/tmp/%s_%s' % (prefix, uuid.uuid4()), 'w') as f:
f.write(value)
In the unit test I will check the following:
open has been called.
The expected file name has been calculated.
openhas been called in write mode.
The write() method of the file handle has been called with the expected argument.
Unittest:
import unittest
from unittest.mock import patch
from my_package.my_module import MyClass
class MyClassTest(unittest.TestCase):
#patch('my_package.my_module.open', create=True)
def test_my_procedure(self, open_mock):
write_mock = open_mock.return_value.write
MyClass.my_procedure('test')
self.assertTrue(open_mock.call_count, 1)
file_name, mode = open_mock.call_args[0]
self.assertTrue(file_name.startswith('/tmp/string_'))
self.assertEqual(mode, 'w')
self.assertTrue(write_mock.called_once_with('test'))
If your methods do something, then I'm sure there should be a logic there. Let's consider this dummy example:
cool = None
def my_static_method(something):
try:
cool = int(something)
except ValueError:
# logs here
for negative test we have:
assertRaises(ValueError, my_static_method(*args))
and for possitive test we can check cool:
assertIsNotNone(cool)
So you're checking if invoking my_static_method affects on cool.
I found the following code snippet that I can't seem to make work for my scenario (or any scenario at all):
def load(code):
# Delete all local variables
globals()['code'] = code
del locals()['code']
# Run the code
exec(globals()['code'])
# Delete any global variables we've added
del globals()['load']
del globals()['code']
# Copy k so we can use it
if 'k' in locals():
globals()['k'] = locals()['k']
del locals()['k']
# Copy the rest of the variables
for k in locals().keys():
globals()[k] = locals()[k]
I created a file called "dynamic_module" and put this code in it, which I then used to try to execute the following code which is a placeholder for some dynamically created string I would like to execute.
import random
import datetime
class MyClass(object):
def main(self, a, b):
r = random.Random(datetime.datetime.now().microsecond)
a = r.randint(a, b)
return a
Then I tried executing the following:
import dynamic_module
dynamic_module.load(code_string)
return_value = dynamic_module.MyClass().main(1,100)
When this runs it should return a random number between 1 and 100. However, I can't seem to get the initial snippet I found to work for even the simplest of code strings. I think part of my confusion in doing this is that I may misunderstand how globals and locals work and therefore how to properly fix the problems I'm encountering. I need the code string to use its own imports and variables and not have access to the ones where it is being run from, which is the reason I am going through this somewhat over-complicated method.
You should not be using the code you found. It is has several big problems, not least that most of it doesn't actually do anything (locals() is a proxy, deleting from it has no effect on the actual locals, it puts any code you execute in the same shared globals, etc.)
Use the accepted answer in that post instead; recast as a function that becomes:
import sys, imp
def load_module_from_string(code, name='dynamic_module')
module = imp.new_module(name)
exec(code, mymodule.__dict__)
return module
then just use that:
dynamic_module = load_module_from_string(code_string)
return_value = dynamic_module.MyClass().main(1, 100)
The function produces a new, clean module object.
In general, this is not how you should dynamically import and use external modules. You should be using __import__ within your function to do this. Here's a simple example that worked for me:
plt = __import__('matplotlib.pyplot', fromlist = ['plt'])
plt.plot(np.arange(5), np.arange(5))
plt.show()
I imagine that for your specific application (loading from code string) it would be much easier to save the dynamically generated code string to a file (in a folder containing an __init__.py file) and then to call it using __import__. Then you could access all variables and functions of the code as parts of the imported module.
Unless I'm missing something?
i can't get the printing of a dict. to work, seen alot exsample codes but none have worked
from UI import ask_info
def main():
mydict = {}
def add(mydict):
info=ask_info()
mydict=info
for i in mydict:
print(mydict[i])
def ask_info():
info1=input("enter the info")
info2=input("enter the info2")
informations=mydict(info1,info2)
return informations
the ask_info is in an different module, if i run this code the print is nothing also if write the dictionary into a file the file is empty. I also have tryed using a class module for this where i have refered to the class module in the "informations=class(info1,info2)" part
As far as I know, dictionaries in Python are not callable and don't work like that. Instead of mydict(info1,info2) you probably want something like mydict[info1] = info2.
Check this link to see how dictionaries work. If you are creating a new dictionary, you can do something like dict([(info1,info2)]) but it does not seem you are trying to do that.
I'm trying to build a simple environment check script for my firm's test environment. My goal is to be able to ping each of the hosts defined for a given test environment instance. The hosts are defined in a file like this:
#!/usr/bin/env python
host_ip = '192.168.100.10'
router_ip = '192.168.100.254'
fs_ip = '192.168.200.10'
How can I obtain all of these values in a way that is iterable (i.e. I need to loop through and ping each ip address)?
I've looked at local() and vars(), but trying do something like this:
for key, value in vars():
print key, value
generates this error:
ValueError: too many values to unpack
I have been able to extract the names of all variables by checking dir(local_variables) for values that don't contain a '__' string, but then I have a list of strings, and I can't figure out how to get from the string to the value of the same-named variable.
First off, I strongly recommend not doing it that way. Instead, do:
hosts = {
"host_ip": '192.168.100.10',
"router_ip": '192.168.100.254',
"fs_ip": '192.168.200.10',
}
Then you can simply import the module and reference it normally--this gives an ordinary, standard way to access this data from any Python code:
import config
for host, ip in config.hosts.iteritems():
...
If you do access variables directly, you're going to get a bunch of stuff you don't want: the builtins (__builtins__, __package__, etc); anything that was imported while setting up the other variables, etc.
You'll also want to make sure that the context you're running in is different from the one whose variables you're iterating over, or you'll be creating new variables in locals() (or vars(), or globals()) while you're iterating over it, and you'll get "RuntimeError: dictionary changed size during iteration".
You need to do vars().iteritems(). (or .items())
Looping over a dictionary like vars() will only extract the keys in the dictionary.
Example.
>>> for key in vars(): print key
...
__builtins__
__name__
__doc__
key
__package__
>>> for key, value in vars().items(): print key, value
...
__builtins__ <module '__builtin__' (built-in)>
value None
__package__ None
key __doc__
__name__ __main__
__doc__ None
Glenn Maynard makes a good point, using a dictionary is simpler and more standard. That being said, here are a couple of tricks I've used sometimes:
In the file hosts.py:
#!/usr/bin/env python
host_ip = '192.168.100.10'
router_ip = '192.168.100.254'
fs_ip = '192.168.200.10'
and in another file:
hosts_dict = {}
execfile('hosts.py', hosts_dict)
or
import hosts
hosts_dict = hosts.__dict__
But again, those are both rather hackish.
If this really is all that your imported file contains, you could also read it as just a text file, and then parse the input lines using basic string methods.
iplistfile = open("iplist.py")
host_addr_map = {}
for line in iplistfile:
if not line or line[0] == '#':
continue
host, ipaddr = map(str.strip, line.split('='))
host_addr_map[host] = ipaddr
iplistfile.close()
Now you have a dict of your ip addresses, addressable by host name. To get them all, just use basic dict-style methods:
for hostname in host_addr_map:
print hostname, host_addr_map[hostname]
print host_addr_map.keys()
This also has the advantage that it removes any temptation any misguided person might have to add more elaborate Python logic to what you thought was just a configuration file.
Here's a hack I use all the time. You got really close when you returned the list of string names, but you have to use the eval() function to return the actual object that bears the name represented by the string:
hosts = [eval('modulename.' + x) for x in dir(local_variables) if '_ip' in x]
If I'm not mistaken, this method also doesn't pose the same drawbacks as locals() and vars() explained by Glen Maynard.
In a Python package, I have a string containing (presumably) the name of a subpackage. From that subpackage, I want to retrieve a tuple of constants...I'm really not even sure how to proceed in doing this, though.
#!/usr/bin/python
"" The Alpha Package
Implements functionality of a base package under the 'alpha' namespace
""
def get_params(packagename):
# Here, I want to get alpha.<packagename>.REQUIRED_PARAMS
pass
So, later in my code I might have:
#!/usr/bin/python
import alpha
alpha.get_params('bravo') # should return alpha.bravo.REQUIRED_PARAMS
alpha.get_params('charlie') # should return alpha.charlie.REQUIRED_PARAMS
If I correctly understand what you want, I think something roughly like this should work:
def get_params(packagename):
module = __import__('alpha.%s' % packagename)
return module.__dict__['REQUIRED_PARAMS']