Creating an object from a string, is it possible? - python

Is it possible to do the following
This works
usethismodule.LoginUsername="my value"
usethismodule.LoginPassword="another value"
But I don't know the second part of the object until the code is being run, I think what I want is this
listofthings=[]
listofthings.append('usethismodule.LoginUsername')
listofthings.append('usethismodule.LoginPassword')
for value in listofthings:
value="A value I set"
This would have the same outcome as the above. Does that make sense?

Indeed, setattr and a dictionary would do the trick.
dictofthings = {
'usethismodule.LoginUsername': 'my value',
'usethismodule.LoginPassword': 'my other value'
}
for k in dictofthings:
setattr(eval(k.split('.')[0]), k.split('.')[1], dictofthings[k])
Hope this helps!

You keep saying usethismodule.<something>. So let's pretend you're right.
Python maintains a dict of currently imported modules in sys.modules. You can look up a module, by name, and get an "object". (A module object, in fact.)
If you have an object in hand, you can either hard-code an access to one of its attributes, or use getattr or setattr on it.
import sys
module_name = "usethismodule" # I don't know where this come from.
utm = sys.modules[module_name]
utm.LoginUsername = "xyzzy"
utm.LoginPassword = "secret123"
# or
pw_attr_name = "passWord" # Maybe you read this from a config file?
setattr(utm, pw_attr_name, "secret123")

Related

How to resolve a global variable in a module?

I have a script as follows
from mapper import Mapper
class A(object):
def foo(self):
print "world"
a = A()
a.foo()
Mapper['test']()
with Mapper defined in the file mapper.py:
Mapper = {'test': a.foo}
where I want to define a function call referencing an object not defined in mapper.py, but in the original code. However the code above gives the error
NameError: name 'a' is not defined
which makes kind of sense, as a is not defined in mapper.py itself. However, is it possible to change the code to let the code do the name resolution in the main code itself, or by the use of globals or something?
To solve this problem I could specify the implementation in mapper.py as a text and use eval in the main code, but I would like to avoid the usage of eval.
Additional information:
The full definition of the function has to be made in mapper.py
It is not known beforehand what the instance a is, or from what clas it is instantiated.
Barring security holes like eval, it's not possible to use a name a in mapper.py unless the name is either defined somewhere in mapper.py or imported from another module. There is no way to just let mapper.py automatically and silently access a value a from a different module.
In addition, if you're using it just in a dict as in your example, a.foo is going to be evaluated as soon as the dict is created. It's not going wait until you actually call the function; as soon as it evaluates a.foo to create the dict, it will fail because it doesn't know what a is.
You could get around this second problem by wrapping the element in a function (using a lambda for brevity):
Mapper = {'test': lambda: a.foo}
. . . but this still won't help unless you can somehow get a to be available inside mapper.py.
One possibility is to parameterize your Mapper by the "mystery" object and then pass that object in from outside:
# mapper.py
Mapper = {'test': lambda a: a.foo}
# other module
from mapper import Mapper
Mapper['test'](a)()
Or, similar to what mgilson suggested, you could "register" the object a with Mapper somehow. This lets you pass the object a only once to register it, and then you don't have to pass it for every call:
# mapper.py
Mapper = {'test': lambda a: Mapper['a'].foo}
# other module
from mapper import Mapper
Mapper['a'] = a
Mapper['test']()()
Note the two sets of parentheses at the end there: one set to evaluate the lambda and extract the function you want to call, and the second set to actually call that function. You could do a similar deal by, instead of using Mapper['a'] as the reference, using a module-level variable:
# mapper.py
Mapper = {'test': lambda: a.foo}
# other module
import mapper
Mapper = mapper.Mapper
mapper.a = a
Mapper['test']()()
Note that this requires you to do import mapper in order to set the module variable in that other module.
You could streamline this somewhat by using a custom class for Mapper instead of a regular dict, and having that class do some work in its __getitem__ to look in a "known location" (e.g., read some module variable) to use as a base for evaluating a. That would be a heavier-weight solution though.
The bottom line is that you simply cannot (again, without the use of eval or other such holes) write code in mapper.py that uses an undefined variable a, and then define a variable a in another module and have mapper.py automatically know about that. There has to be some line of code somewhere that "tells" mapper.py what value of a you want it to use.
I'm not sure I completely follow, but a could "register" it's method with Mapper from anywhere which has a reference to Mapper:
#mapping.py
Mapper = {}
and then:
#main.py
from mapping import Mapper
#snip
a = A()
Mapper['test'] = a.foo #put your instance method into the Mapper dict.
#snip
Mapper['test']()

lazy load dictionary

I have a dictionary called fsdata at module level (like a global variable).
The content gets read from the file system. It should load its data once on the first access. Up to now it loads the data during importing the module. This should be optimized.
If no code accesses fsdata, the content should not be read from the file system (save CPU/IO).
Loading should happen, if you check for the boolean value, too:
if mymodule.fsdata:
... do_something()
Update: Some code already uses mymodule.fsdata. I don't want to change the other places. It should be variable, not a function. And "mymodule" needs to be a module, since it gets already used in a lot of code.
I think you should use Future/Promise like this https://gist.github.com/2935416
Main point - you create not an object, but a 'promise' about object, that behave like an object.
You can replace your module with an object that has descriptor semantics:
class FooModule(object):
#property
def bar(self):
print "get"
import sys
sys.modules[__name__] = FooModule()
Take a look at http://pypi.python.org/pypi/apipkg for a packaged approach.
You could just create a simple function that memoizes the data:
fsdata = []
def get_fsdata:
if not fsdata:
fsdata.append(load_fsdata_from_file())
return fsdata[0]
(I'm using a list as that's an easy way to make a variable global without mucking around with the global keyword).
Now instead of referring to module.fsdata you can just call module.get_fsdata().

Dynamically call python-class defined in config-file

I have a config.cfg which I parse using the python-module ConfigParser. In one section I want to configure assignments of the form fileextension : ClassName. Parsing results in the following dictionary:
types = {
"extension1" : "ClassName1",
"extension2" : "ClassName2"
}
EDIT: I know I can now do:
class_ = eval(types[extension])
foo = class()
But I was given to understand that eval is evil and should not be used.
Do you know a nicer way to dynamically configure which file-extension results in which class?
You could use eval, if the class name in the config file exactly matches the class names in your python code (and if the classes are in scope!), but ..... eval is evil (a coincidence that there's only one letter difference? I think not!)
A safer way to do it would be to add an extra dictionary that maps from configuration class name to python class name. I'd do this because:
configuration files don't have to know about your code's names
can change config files without changing code and vice versa
it avoids eval
So it'd look something like:
mappingDict = {"ClassName1" : MyPythonClass1,
"ClassName2" : MyPythonClass2, ... }
# keys are strings, values are classes
Then you perform a lookup using the value from the config file:
myClassName = types['extension1']
myClass = mappingDict[myClassName]
If module is the module the class named classname lives in, you can get the class object using
class_ = getattr(module, classname)
(If the class lives in the main module, use import __main__ to get a module object for this module.)
To look up the class in the current module's global scope, use
class_ = globals()[classname]
I think a static dictionary as in Matt's answer is the better solution.

How to extract and then refer to variables defined in a python module?

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.

SCons problem - dont understand Variables class

I'm working on an SConstruct build file for a project and I'm trying to update from Options to Variables, since Options is being deprecated. I don't understand how to use Variables though. I have 0 python experience which is probably contributing to this.
For example, I have this:
opts = Variables()
opts.Add('fcgi',0)
print opts['fcgi']
But I get an error:
AttributeError: Variables instance has no attribute '__getitem__':
Not sure how this is supposed to work
Typically you would store the variables in your environment for later testing.
opts = Variables()
opts.Add('fcgi',0)
env = Environment(variables=opts, ...)
Then later you can test:
if env['fcgi'] == 0:
# do something
That specific error tells you that class Variables hasn't implemented python's __getitem__ interface which would allow you to use [ ...] on opts. If all you want to do is print out your keys, the Variables documentation seems to indicate that you can iterate over your keys:
for key in opts.keys():
print key
Or you can print out the help text:
print opts.GenerateHelpText()

Categories