custom plugin architecture: how to see parent namespace?

E

escalation746

I've got a namespace query that amounts to this: How can an imported
function see data in the parent custom namespace? I have read through
numerous posts which skirt this issue without answering it.

To illustrate, create plugin.py with a couple of functions. The second
will obviously fail.

----
def Hello():
print 'hello'

def ViewValuable():
print VALUABLE
----

Then create master.py which loads the plugin at runtime, later running
various code fragments against it.

----
# location of plugin module
filespec = '/path/to/plugins/plugin.py'
filepath, filename = os.path.split(filespec)
filename = os.path.splitext(filename)[0]

# add to system path
if filepath not in sys.path:
sys.path.append(filepath)

# import into our namespace
space = __import__(filename, globals(), locals(), [])
namespace = space.__dict__

# sometime later in the code... define a new function
def _plus():
print 'plus'

# add that to our namespace
namespace.update({'Plus': _plus, 'VALUABLE': 'gold'})

# run custom code
code = """
Hello()
Plus()
Valuable()
"""
exec code in namespace
----

This code will echo the lines:
hello
plus

Followed by a traceback for:
NameError: global name 'VALUABLE' is not defined

The question is: How do I get a function in plugin.py to see VALUABLE?
Using external storage of some sort is not viable since many different
instances of plugin.py, all with different values of VALUABLE, might
be running at once. (In fact VALUABLE is to be a key into a whole
whack of data stored in a separate module space.)

Extensive modifications to plugin.py is also not a viable approach,
since that module will be created by users. Rather, I need to be able
to pass something at execution time to make this happen. Or create an
access function along the lines of _plus() that I can inject into the
namespace.

Any help, please? I've been losing sleep over this one.

-- robin
 
F

faulkner

I've got a namespace query that amounts to this: How can an imported
function see data in the parent custom namespace? I have read through
numerous posts which skirt this issue without answering it.

To illustrate, create plugin.py with a couple of functions. The second
will obviously fail.

----
def Hello():
print 'hello'

def ViewValuable():
print VALUABLE
----

Then create master.py which loads the plugin at runtime, later running
various code fragments against it.

----
# location of plugin module
filespec = '/path/to/plugins/plugin.py'
filepath, filename = os.path.split(filespec)
filename = os.path.splitext(filename)[0]

# add to system path
if filepath not in sys.path:
sys.path.append(filepath)

# import into our namespace
space = __import__(filename, globals(), locals(), [])
namespace = space.__dict__

# sometime later in the code... define a new function
def _plus():
print 'plus'

# add that to our namespace
namespace.update({'Plus': _plus, 'VALUABLE': 'gold'})

# run custom code
code = """
Hello()
Plus()
Valuable()
"""
exec code in namespace
----

This code will echo the lines:
hello
plus

Followed by a traceback for:
NameError: global name 'VALUABLE' is not defined

The question is: How do I get a function in plugin.py to see VALUABLE?
Using external storage of some sort is not viable since many different
instances of plugin.py, all with different values of VALUABLE, might
be running at once. (In fact VALUABLE is to be a key into a whole
whack of data stored in a separate module space.)

Extensive modifications to plugin.py is also not a viable approach,
since that module will be created by users. Rather, I need to be able
to pass something at execution time to make this happen. Or create an
access function along the lines of _plus() that I can inject into the
namespace.

Any help, please? I've been losing sleep over this one.

-- robin

sys._getframe(1).f_locals
 
E

escalation746

faulkner said:
sys._getframe(1).f_locals

Brilliant. That one's pretty well hidden and labeled "should be used
for internal and specialized purposes only". Guess I'm officially
special. :)

To implement this with minimal requirements on the author of the
plugin, I created a function in master.py:
def GetKey():
ns = sys._getframe(2).f_locals
return ns['VALUABLE']

Now the plugin gets the useful info simply:
import master
print master.GetKey()

Though it would be nice if this info could somehow be "injected" into
the namespace of plugin.py without this, I can live with two lines.

Thanks!

-- robin
 
W

Wojciech =?iso-8859-2?Q?Mu=B3a?=

escalation746 said:
def ViewValuable():
^^^^^^^^^^^^
[...]
code = """
Hello()
Plus()
Valuable() ^^^^^^^^
"""

These names don't match. I replaced Valuable() with proper name,
and everything work fine.

w.
 
E

escalation746

Wojciech said:
These names don't match. I replaced Valuable() with proper name,
and everything work fine.

That was a result of a transcription error when posting to the
newsgroup. My actual test code did not have this error but
nevertheless did not work.

However, copying the code I *did* post to the newsgroup and making
that change you pointed out... the code indeed worked as you claimed!

Two wrongs making a right?

I am sure when I look at this tomorrow it will not work again. :)

-- robin
 
E

escalation746

Jorge said:
Your motivation looks a lot like what is solved by setuptools, eggs and
entry points.

Though that problem domain looks different (installation, app
dependencies), you are no doubt correct that there is functionality
overlap. However, that is a maximal solution while mine is minimal and
hence (maybe) of use to people who prefer a couple dozen lines of code
to an entire package.

-- robin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top