Re: Editing a function in-memory and in-place

2006-04-28 Thread Ian Bicking
Thanks for the answers, very helpful.  I think I'm going to give
Peter's hack a try, as it's actually quite close to what I'm trying to
do -- I get the source for the new function, then that lets me make the
old function become the new one.  But I'll probably also use Michael's
solution for class editing.

Now I just have to figure out how to take in-memory structures and turn
them into Python source code.  Hmm... that actually leads me back to
Michael's solution more, since in that model you are always dealing
with source, and if you faithfully reproduce the source then you should
more-or-less reproduce the same structures.  Hmm... challenging.  I
guess this is one motivation for languages like Smalltalk to use an
image, because they don't have to serialize code as source.

Of course, I could use one of those pickle alternatives that knows how
to pickle live objects; but that takes the project much further from
normal Python.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Editing a function in-memory and in-place

2006-04-27 Thread Michael Spencer
Ian Bicking wrote:
> I got a puzzler for y'all.  I want to allow the editing of functions
> in-place.  I won't go into the reason (it's for HTConsole --
> http://blog.ianbicking.org/introducing-htconsole.html), except that I
> really want to edit it all in-process and in-memory.  So I want the
> identity of the function to remain the same, even as I edit the body
> and hopefully the signature too.
> 
> Well, the reason is that I want to edit any function object, without
> having to know who has a reference to the function.  This way editing a
> function or a method or a property.fget can all be done in the same
> way.
> 
> The func_code attributes of functions is writable, but I don't know how
> to create the proper code object.  Just compiling a new body isn't good
> enough.
> 


The experimental module below updates many of the builtin types in-place, 
including functions.  Functions in particular are handled by 
update_FunctionType.  I use this in my own development environment to edit live 
code i.e., as a better reload.


Michael


"""Update live code with new source.

Example:
 >>> source1 = "def func1(a): return 2*a"
 >>> namespace = {}
 >>> exec source1 in namespace
 >>> func1 = namespace["func1"]
 >>> func1(2)
 4
 >>> source2 = "def func1(a, b): return 2*a+b"
 >>> exec_update(namespace, source2, verbosity=2)
 Updating: ,
 .func1 Updated
 True
 >>> func1(2,2)
 6
 >>>
"""


import types
import gc

class UpdateException(Exception): pass

def exec_update(namespace, source, name="", verbosity = 1):
 module_proxy.verbosity = verbosity
 if verbosity == 2:
 print "Updating: %s, %s" % (type(namespace), name)
 if isinstance(namespace, types.ModuleType):
 proxy = module_proxy(namespace)
 elif isinstance(namespace, (type, types.ClassType)):
 proxy = cls_proxy(namespace)
 elif isinstance(namespace, dict):
 proxy = dict_proxy(namespace, name)
 else:
 raise UpdateException, "Unrecognized namespace type: %s" % 
type(namespace)
 exec source in proxy.dict, proxy
 return True


class module_proxy(object):
 DO_NOT_COPY = ()
 verbosity = 1
 def __init__(self, module, name = ""):
 self.dict = module.__dict__
 self.namespace = module
 self.name = getattr(module,"__name__", name)

 def __contains__(self, key):
 return key in self.dict

 def _setitem(self,key,value):
 self.dict[key] = value

 def _delitem(self, key):
 del self.dict[key]

 def __getitem__(self, key):
 return self.dict[key]

 def __setitem__(self, key, value):
 try:
 obj  = self.dict[key]
 except KeyError:
 if self.verbosity >= 1:
 print "** %s.%s=%s (Binding)" % (self.name, key, repr(value))
 self._setitem(key, value)
 return True
 try:
 if update(obj, value):
 if self.verbosity >= 1:
 print "%s.%s Updated" % (self.name, key)
 return True
 else:
 if self.verbosity >= 2:
 print "%s.%s No change" % (self.name, key)
 return False
 except UpdateException:
 if self.verbosity >= 1:
 print "** %s.%s=>%s (Rebinding)" % (self.name, key, 
repr(value))
 self._setitem(key, value)
 return True

 def __delitem__(self, key):
 if self.verbosity >= 1:
 print "** del %s.%s" % (self.name, key)
 self._delitem(key)

 def update_ns(self, other_dict, delete_missing=False, skip = ()):
 dirty = False
 if delete_missing:
 for attr in self.dict.keys():
 if not((attr in other_dict) or (attr in skip)):
 dirty = True
 del self[attr]
 for to_attr, to_obj in other_dict.iteritems():
 if to_attr in skip:
 continue
 dirty |= self.__setitem__(to_attr, to_obj)
 return dirty

class dict_proxy(module_proxy):
 def __init__(self, my_dict, name = ""):
 self.dict = my_dict
 self.namespace = None
 self.name = name


class cls_proxy(module_proxy):

 def _setitem(self,key,value):
 setattr(self.namespace,key,value)

 def _delitem(self, key):
 delattr(self.namespace, key)

 def update_cls(self, other):
 DONOTCOPY = set(["__name__","__bases__","__base__","__dict__",
 "__doc__","__weakref__","__module__"])

 # This will often fail if they are not equal, so find out first!
 obj = self.namespace
 try:
 obj.__bases__ = other.__bases__
 except TypeError, err:
 raise UpdateException, err

 fromdict = obj.__dict__
 todict = other.__dict__
 obj_slots = set(getattr(obj, "__slots__", ()))
 

Re: Editing a function in-memory and in-place

2006-04-27 Thread bruno at modulix
Peter Otten wrote:
(snip)
> 
> Can you cheat and just assign another known good func_code object?
def hello(): print "hello"
> ...
def world(): print "world"
> ...
def use_it(hello=hello, world=world):
> ... hello()
> ... world()
> ...
use_it()
> hello
> world
world.func_code = hello.func_code
use_it()
> hello
> hello
hello, world
> (, )

+1 H2OTW !-)

(NB : H2 -> Horrible Hack)

-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in '[EMAIL PROTECTED]'.split('@')])"
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Editing a function in-memory and in-place

2006-04-26 Thread Peter Otten
Ian Bicking wrote:

> I got a puzzler for y'all.  I want to allow the editing of functions
> in-place.  I won't go into the reason (it's for HTConsole --
> http://blog.ianbicking.org/introducing-htconsole.html), except that I
> really want to edit it all in-process and in-memory.  So I want the
> identity of the function to remain the same, even as I edit the body
> and hopefully the signature too.
> 
> Well, the reason is that I want to edit any function object, without
> having to know who has a reference to the function.  This way editing a
> function or a method or a property.fget can all be done in the same
> way.
> 
> The func_code attributes of functions is writable, but I don't know how
> to create the proper code object.  Just compiling a new body isn't good
> enough.

Can you cheat and just assign another known good func_code object?

>>> def hello(): print "hello"
...
>>> def world(): print "world"
...
>>> def use_it(hello=hello, world=world):
... hello()
... world()
...
>>> use_it()
hello
world
>>> world.func_code = hello.func_code
>>> use_it()
hello
hello
>>> hello, world
(, )

Peter

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Editing a function in-memory and in-place

2006-04-26 Thread Terry Reedy

"Ian Bicking" <[EMAIL PROTECTED]> wrote in message 
news:[EMAIL PROTECTED]
>
> The func_code attributes of functions is writable, but I don't know how
> to create the proper code object.  Just compiling a new body isn't good
> enough.

Did you directly compile the body or compile a function and then extract 
the code object?  In any case, if you need to patch the code object and 
cannot do so directly due to read-only fields, this may help:

>>> import new
>>> dir(new)
['__builtins__', '__doc__', '__file__', '__name__', 'classobj', 'code', 
'function', 'instance', 'instancemethod', 'module']
>>> help(new.code)
Help on class code in module __builtin__:

class code(object)
 |  code(argcount, nlocals, stacksize, flags, codestring, constants, names,
 |varnames, filename, name, firstlineno, lnotab[, freevars[, 
cellvars]])
 |
 |  Create a code object.  Not for the faint of heart.
 |
 |  Methods defined here:
...

Terry Jan Reedy



-- 
http://mail.python.org/mailman/listinfo/python-list