Escualo
Escualo

Reputation: 42072

Populating namespace within a module before loading it

I designed a configuration mechanism in Python, where certain objects can operate in special ways to define problems in our domain.

The user specifies the problem by using this objects in a "config-file" manner. For instance:

# run configuration
CASES = [
 ('Case 1', Item('item1') + Item('item2') + Item('item3')),
 ('Case 2', Item('item1') + Item('item4')),
]

DATA = {
 'Case 1' = {'Piece 1': 'path 1'},
 'Case 2' = {'Piece 1': 'path 2'},
}

The Item objects are, of course, defined in a specific module. In order to use them you have to issue an import statement: from models import Item (of course, my actual imports are more complex, not a single one).

I would like the user to simply write the configuration presented, without having to import anything (users very easily can forget this).

I thought of reading the file as text, and creating a secondary text file with all the appropriate imports at the top, write that to a file, and import that file, but this seems clumsy.

Any advice?

Edit:

The workflow of my system is somewhat similar to Django, in that the user defines the "Settings" in a python file, and runs a script which imports that Settings file and does things with it. That is where I would like this functionality, to tell Python "given this namespace (where Item means something in particular), the user will provide a script - execute it and hand me the result so that I can spawn the different runs".

Upvotes: 3

Views: 271

Answers (2)

mouad
mouad

Reputation: 70021

1) the first thing that i have in mind is to offer to the user the generation of your config file; how so ?

you can add an argument in the script that launch your application :

$ python application_run.py --generate_settings 

this will generate a config file with a skeleton of different import that the user should not have to add every time, something like this:

import sys
from models import Item

# Complete the information here please !!!
CASES = []
DATA = {}

2) a second way is to use execfile() , you can for this create a script that will read the settings.py:

root_settings.py

# All import defined Here.
from Model import Item
...

execfile('settings.py')

And now to read the settings file info just import the root_settings, by the way all variable that have been defined in settings.py are now in root_settings.py namespace .

Upvotes: 0

Katriel
Katriel

Reputation: 123622

From the eval help:

>>> help(eval)
Help on built-in function eval in module __builtin__:

eval(...)
    eval(source[, globals[, locals]]) -> value

    Evaluate the source in the context of globals and locals.
    The source may be a string representing a Python expression
    or a code object as returned by compile().
    The globals must be a dictionary and locals can be any mapping,
    defaulting to the current globals and locals.
    If only globals is given, locals defaults to it.

That is, you can pass in an arbitrary dictionary to use as the namespace for an eval call.

with open(source) as f:
    eval(f.read, globals(), {'Item': Item}) 

Why have you decided that the user needs to write their configuration file in pure Python? There are many simple human-writable languages you could use instead. Have a look at ConfigParser, for instance, which reads basic configuration files of the sort Windows uses.

[cases]
case 1: item1 + item2 + item3
case 2: item1 + item4

[data]
case 1: piece1 - path1
case 2: piece1 - path2

Upvotes: 1

Related Questions