473,411 Members | 1,889 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,411 software developers and data experts.

Editing a function in-memory and in-place

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.

Apr 27 '06 #1
5 1956

"Ian Bicking" <ia**@colorstudy.com> wrote in message
news:11**********************@t31g2000cwb.googlegr oups.com...

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

Apr 27 '06 #2
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

(<function hello at 0x402904fc>, <function world at 0x40290534>)

Peter

Apr 27 '06 #3
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
worldworld.func_code = hello.func_code
use_it() hello
hellohello, world

(<function hello at 0x402904fc>, <function world at 0x40290534>)


+1 H2OTW !-)

(NB : H2 -> Horrible Hack)

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Apr 27 '06 #4
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: <type 'dict'>,
.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__", ()))
other_slots = set(getattr(other, "__slots__", ()))
if other_slots > obj_slots:
raise UpdateException, "Can't add slots %s" % \
list(other_slots - obj_slots)

return self.update_ns(todict, delete_missing=True, skip = DONOTCOPY |
obj_slots)

##TODO - Instances with __slots__ (see decimal.Decimal)
class instance_proxy(dict_proxy):
def __init__(self, my_obj, name = ""):
self.dict = my_obj.__dict__
self.namespace = my_obj
self.name = name
# Specialized updaters by type
# Each updater must return: True, False or raise UpdateException
# False: no change required - new object is equal to the old
# True: object was successfully updated
# UpdateException - object could not be updated in place. Caller must
# then decide whether to re-bind

def update_classmethod(obj, other):
# Massive hack. classmethod (and staticmethod) do not expose their
# underlying callable to Python. But they *seem* always to have
# one reference - which must be to the callable.
obj_refs = gc.get_referents(obj)
other_refs = gc.get_referents(other)
if len(obj_refs) != len(other_refs) != 1:
raise UpdateException, "Too many references from classmethod"
return update(obj_refs[0], other_refs[0])

update_staticmethod = update_classmethod

def update_classmethod_FunctionType(obj, other):
obj_refs = gc.get_referents(obj)
if len(obj_refs) != 1:
raise UpdateException, "Too many references from classmethod"
return update(obj_refs[0], other)

def update_property(obj, other):
# These are read-only attributes, so unless we can update them
# in-place, update_property will fail
dirty = False
dirty |= update(obj.fget, other.fget)
dirty |= update(obj.fset, other.fset)
dirty |= update(obj.fdel, other.fdel)
dirty |= update(obj.__doc__, other.__doc__)
return dirty
def update_FunctionType(obj, other):
# Note this applies only to Python-defined functions
dirty = False
for attr in ("func_code", "func_defaults", "func_dict", "func_doc",
"func_globals"):
try:
obj_attr, other_attr = getattr(obj, attr), getattr(other,attr)
except AttributeError, err:
# missing attribute means can't update the function
raise UpdateException, err
try:
# If possible, update the function attributes in-place
# this preserves, in particular, func_defaults
dirty |= update(obj_attr, other_attr)
except UpdateException:
# If we can't update the function attribute in place
# go ahead and overwrite it
dirty = True
setattr(obj, attr, other_attr)
return dirty

def update_MethodType(obj, other):
# No need to update the class/object bindings
return update_FunctionType(obj.im_func, other.im_func)

def update_MethodType_FunctionType(obj, other):
return update_FunctionType(obj.im_func, other)

def update_list(obj, other):
if obj == other:
return False
obj[:] = other
return True

def update_dict(obj, other):
if obj == other:
return False
obj.clear()
obj.update(other)
return True

def update_deque(obj, other):
if obj == other:
return False
obj.clear()
obj.extend(other)
return True

def update_array(obj, other):
if obj == other:
return False
if obj.typecode != other.typecode:
raise UpdateException, "Can't change typecode of array"
obj[:] = other
return True
def update_tuple(obj, other):
# We go to some additional lengths with tuples
if obj == other:
return False
if len(obj) == len(other):
dirty = False
for ob1, ob2 in zip(obj, other):
# This will raise UpdateException if any of the members
# are not updatable
dirty |= update(ob1, ob2)
return dirty
raise UpdateException, "Unequal tuples"

update_set = update_dict

def update_type(obj, other):
proxy_cls = cls_proxy(obj)
return proxy_cls.update_cls(other)

update_ClassType = update_type
def update(obj, other):
if obj is other:
return False
type_pair = type(obj), type(other)
#name = getattr(obj,"__name__", "")
try:
update_method = _method_cache[type_pair]
except KeyError:
pass
else:
#print "UpdateType %r" % obj
return update_method(obj, other)

if type_pair[0] == type_pair[1]:
if isinstance(obj, (object, types.InstanceType)):
try:
obj_dict, other_dict = obj.__dict__, other.__dict__
except AttributeError:
pass
else:
obj_dict_proxy = instance_proxy(obj)
return obj_dict_proxy.update_ns(other_dict, True)

if isinstance(obj, IMMUTABLE_TYPES):
if obj == other:
return False

raise UpdateException, "Can't update %s to %s" % type_pair

# Can't update these, but if they compare equal, there's no need to
import datetime
IMMUTABLE_TYPES = (bool, int, long, float, complex,
buffer, basestring, slice,
types.BuiltinFunctionType, types.BuiltinMethodType, types.CodeType,
types.DictProxyType,
datetime.date, datetime.time, datetime.timedelta, datetime.tzinfo)

del datetime

def _get_types():
from collections import deque
from array import array
d= locals()
d.update(types.__dict__)
return d

def _get_method_cache():
cache = {}
type_dict = _get_types()
for name, obj in globals().items():
if name.startswith("update_"):
fromtypename, totypename = name.rsplit("_", 2)[-2:]
if fromtypename == "update":
fromtypename = totypename
fromtype = eval(fromtypename, type_dict)
totype = eval(totypename, type_dict)
cache[(fromtype,totype)] = obj
return cache

_method_cache = _get_method_cache()

Apr 27 '06 #5
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.

Apr 28 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

383
by: John Bailo | last post by:
The war of the OSes was won a long time ago. Unix has always been, and will continue to be, the Server OS in the form of Linux. Microsoft struggled mightily to win that battle -- creating a...
4
by: Jerry Khoo | last post by:
i am currently working on an assignment that requires the program to manage the files like editing file content, modifying file content, and deleting file contents. My question is what sort of...
1
by: ___Newbie___ | last post by:
Hello, What is the best way to implement a form based editing? The user would select first from a list control (highlighted selection) ? e.g. through a listbox or datagrid. Then, select from...
0
by: Fred K. Augustine, Jr | last post by:
After upgrading from Visual Web Developer Beta2 to the final release version, web forms that contained GridView controls set up for data editing stopped working properly. No error is produced but...
5
by: dan heskett | last post by:
I'd like to modify the standard .net list box to allow in place editing of the data. I am owner drawing a complex listbox item, but first off, is this even advisable? I have a simple list and...
12
by: Thomas Bartkus | last post by:
Does anyone use emacs together with both WordStar key bindings and python mode? I'm afraid that Wordstar editing key commands are burned R/O into my knuckles! I would like to play with emacs...
8
by: D | last post by:
Hi, I currently have a Python app with a Tkinter GUI frontend that I use for system administration. Everytime it launches, it reads a text file which contains info about each host I wish to...
0
by: gwanglu | last post by:
ProAOS offers you a high quality photo and video editing for your adult sites! We guarantee you customer satisfaction and a very reliable and professional work. If you want to try our services you...
7
by: Rainy | last post by:
Hi, did anyone make a good set of scripts for editing Python in Vim? I know there is one on vim.org but it isn't very advanced. thx..
2
by: Steve555 | last post by:
Hi, I'm creating an object CSub, which is sub-classed from CMaster. The constructor for either takes a struct as an argument: CSub:: CSub(BasicModel *inModel : CMaster(inModel) and this...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.