Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I load all keys from a dict as local variables, a better aproach?

Tags:

python

Giving this dictionary:

>>> options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}}

What would be the best way to get this?:

>>> foo(options)
>>> print DATABASES
{'default': {'ENGINE': 'django.db.backends.sqlite3'}}

I am solving this as locals().update(options), but I was thinking, if there is maybe a better solution.

like image 672
Mario César Avatar asked Jan 10 '11 19:01

Mario César


2 Answers

import inspect

allowed_vars = set(["min_", "max_", "path", ...])
def update_globals(dic):
    caller_frame = inspect.currentframe(1)
    globals = caller_frame.f_globals
    # here, you _could_ simply do globals.update(dic) 
    # but it is  evil
    for key, value in dic.items():
        #here you should carefully verify each key, and value for not
        #not dangerous pairs, with stuff like:
        #if key not in allowed_vars:
        #    sys.stderr.write("Warning: invalid variable in configuration update\n")
        #     continue
        #if type(value) not in (string, int, float):
        #    #(issue error)
        #    continue
        globals[key] = value

Example:

>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> update_globals({"a": 5})
>>> a
5

update 2016-06 A couple of weeks ago I had put together the extradict Python package - it is available on pypi now. One of its features is the MapGetter context manager that allows exactly what is being asked for by doing something along:

from extradict import MapGetter

def myfunc():
    options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}}
    with MapGetter(options) as options:
         from options import DATABASES
 ...

And other normal "from .... import .... " usages, but from a dictionary or mapping object (including a default dict).

like image 85
jsbueno Avatar answered Sep 22 '22 13:09

jsbueno


As goldmab noted, modifying the output of locals() inside a function won't work:

SyntaxError: invalid syntax
>>> def foo():
...     locals().update({'a': 1})
...     print a
... 
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in foo
NameError: global name 'a' is not defined

This isn't really a very clean way either, but it would do the job:

>>> def foo():
...     options = {'DATABASES': {'default': {'ENGINE': 'django.db.backends.sqlite3'}}}
...     for k, v in options.items():
...         exec('%s = v' % k)
...     print DATABASES
... 
>>> foo()
{'default': {'ENGINE': 'django.db.backends.sqlite3'}}

Note, by the way, that each key in your dict would need to be ok as a variable. So for example, if the dictionary contained 'DATABASE-USERNAME' as a key, trying to assign that to a variable would cause an exception. Further, doing this would make you vulnerable to code injection attacks if you get the options dictionary from an untrustworthy source. (A key could say something like, "import os ; os.system('sudo adduser scriptkiddie') ; ..."

like image 45
Ken Kinder Avatar answered Sep 18 '22 13:09

Ken Kinder