Import into specified namespace

F

Fritz Bosch

Hi experts

Is is possible to import/manipulate a module such that
I can supply its __dict__?

I want to supply my own dict subclass object to be filled
by the import, e.g. a class like:
.... def __setitem__(self,name,val):
.... print name, val
.... dict.__setitem__(self,name,val)

__dict__ is a readonly attribute, so I can't change it after
the import, i.e. the following doesn't work:
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: readonly attribute

I have experimented with new.module(), __import__(),
imp.*, exec/eval/execfile+globals/locals but to no avail.

Is there any way to do this?

Thanks
Fritz
 
A

Alex Martelli

Fritz Bosch said:
__dict__ is a readonly attribute, so I can't change it after
the import, i.e. the following doesn't work:

Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: readonly attribute

Why not sys.modules['sys'] = mydic instead of trying to rebind
sys.__dict__? You can't affect those other modules which have ALREADY
imported sys, yourself included (but as for you, you can remedy that
easily -- sys = sys.modules['sys'] = mydic...), but otherwise you should
be OK. sys.__dict__.update(mydic) as the last statement might also be
an alternative (and if it works for your purposes, it's cleaner than
rebinding sys.modules['sys']!-).


Alex
 
F

Fritz Bosch

...
Why not sys.modules['sys'] = mydic instead of trying to rebind
sys.__dict__? You can't affect those other modules which have ALREADY
imported sys, yourself included (but as for you, you can remedy that
easily -- sys = sys.modules['sys'] = mydic...), but otherwise you should
be OK. sys.__dict__.update(mydic) as the last statement might also be
an alternative (and if it works for your purposes, it's cleaner than
rebinding sys.modules['sys']!-).

Thanks for the hint. I actually want a different behavior for the
namespace, so the second suggestion (though cleaner) won't work for
me. In fact, I had to modify the first to get what I want, namely a
namespace (for a module) with a reverse lookup capability, i.e. given
an object, it returns the object's name (if any) inside the namespace.

I eventually got following to run:

Assume a small module 'mymod.py', for which I need a namespace with
reverse lookup capability:
-------------------------------------------------------------
import sys

def fn():
name = fn.__module__
# print the id of this module in sys.modules, along with the ids
# of the function and current globals, and the module's dict
print 'mymod name:%s id(sys.modules[name]):%s' % (
name, id(sys.modules[name]))
print ' id(fn.func_globals):%s id(globals()):%s \
id(sys.modules[name].__dict__):%s' % (
id(fn.func_globals), id(globals()),
id(sys.modules[name].__dict__))
-------------------------------------------------------------

To do this, I have defined following namespace.py module:
-------------------------------------------------------------
import sys
import os

class RNameSpace(dict):
def __init__(self, *args, **kw):
dict.__init__(self, *args, **kw)
self.__rdict = {}
for name, val in self.items():
self.__rdict[id(val)] = name
def __setitem__(self, name, val):
if name in self:
del self.__rdict[id(self[name])]
dict.__setitem__(self, name, val)
self.__rdict[id(val)] = name
def update(self, other):
for name, val in other.items():
self[name] = val
def __delitem__(self, name):
if name in val:
del self.__rdict[id(self[name])]
dict.__delitem__(self, name)
def rlookup(self, obj):
return self.__rdict[id(obj)]

class Module(object):
def __init__(self, mod_name, namespace=None):
if namespace is None:
namespace = RNameSpace()
if isinstance(namespace, RNameSpace):
self.__dict__ = namespace
else:
self.__dict__ = RNameSpace(namespace)
module = __import__(mod_name)
self.__dict__.update(module.__dict__)
def reload(self):
file = os.path.splitext(self.__file__)[0] + '.py'
execfile(file, self.__dict__)
def install(self):
mod_name = self.__name__
sys.modules[mod_name] = self

if __name__ == '__main__':
ns = RNameSpace(a=1,b=2)
c1 = 3
ns['c']=c1
a1 = ns['a']
print ns.rlookup(a1), ns.rlookup(c1)

print "create Module md from 'mymod' to use RNameSpace:"
md = Module('mymod')
print 'id(md):%s id(md.__dict__):%s' % (id(md), id(md.__dict__))

print "\nnote that md.fn still uses original namespace:"
md.fn()

print '\nreload the file - now md.fn used the RNameSpace:'
md.reload()
md.fn()

print '\nan import still uses the original namespace:'
import mymod
mymod.fn()

print '\ninstall the module - subsequent imports \
use the altered namespace:'
md.install()
import mymod
mymod.fn()
-------------------------------------------------------------

From the above it can be seen that it was necessary to create a
module-like object with the specified namespace and to call execfile
with this namespace ? I could find no other way to make the
classes/functions inside mymod use the namespace. Replacing the
sys.modules entry with this object then causes subsequent imports to
use the module-like object.

B.t.w. am I re-inventing the wheel here? Is there another way to get
the name from given an object id?

Fritz
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top