Patches item #1402289, was opened at 2006-01-11 01:24 Message generated for change (Comment added) made by loewis You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1402289&group_id=5470
Please note that this message will contain a full copy of the comment thread, including the initial issue submission, for this request, not just the latest update. Category: Core (C code) Group: Python 2.5 Status: Open Resolution: None Priority: 5 Private: No Submitted By: crutcher (crutcher_gmail) Assigned to: Raymond Hettinger (rhettinger) Summary: Allow mappings as globals (was: Fix dictionary subclass ...) Initial Comment: There is an inconsistancy in the way that dictionary subclasses behave when they are used as as namespaces in execs. Basically, while python 2.4 permits the usage of dictionary subclasses for local environments, it still bypasses the subclass functions and uses the C API for global environments. The attached patch (and unittest!) addresses this issue. I'm pretty sure we keep the fast path in this. ---------------------------------------------------------------------- >Comment By: Martin v. Löwis (loewis) Date: 2007-02-15 10:55 Message: Logged In: YES user_id=21627 Originator: NO Raymond, do you think you can make it this March? If not, please unassign. ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-03-30 20:12 Message: Logged In: YES user_id=1424288 Are you going to get to this? ---------------------------------------------------------------------- Comment By: Raymond Hettinger (rhettinger) Date: 2006-02-21 14:28 Message: Logged In: YES user_id=80475 Crutcher, this looked good on my first read-through. Will go through it in detail sometime in March. ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-30 20:10 Message: Logged In: YES user_id=1424288 doh, forgot to check the 'upload' box ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-30 18:08 Message: Logged In: YES user_id=1424288 I have reworked and extended this patch so that arbitrary mappings are permitted for globals, not just dictionary subtypes. This touched a good deal more code. Please use the updated version. ---------------------------------------------------------------------- Comment By: Armin Rigo (arigo) Date: 2006-01-25 19:20 Message: Logged In: YES user_id=4771 I will review and check-in your patch, I think it's a good idea despite the added code complexity. ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-25 04:38 Message: Logged In: YES user_id=1424288 currently chasing through the PyFrame code and the EXEC_STMT code to make globals generic mappings, will update this patch yet again. ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-22 10:19 Message: Logged In: YES user_id=1424288 I've fixed up the exception case, and extended the test case to check for it. Is there anything else I can do to get this in? ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-22 06:11 Message: Logged In: YES user_id=1424288 I'm going to fix the missed exception test this weekend, and try to get an updated patch to you. ---------------------------------------------------------------------- Comment By: Armin Rigo (arigo) Date: 2006-01-14 10:54 Message: Logged In: YES user_id=4771 Provided this can be done with no measurable performance hit, I guess that I'm fine with the idea. The patch needs a bit more work, though: I don't see why it should accept dict subclasses as globals but not arbitrary mappings (as it now does for the locals). This is mainly an issue of removing a few checks in various places, like EXEC_STMT and the eval() and execfile() built-ins. There is a missing exception check/clear in the part about LOAD_NAME, after the PyObject_GetItem(f->f_globals, w). A side note: in the current trunk already, LOAD_GLOBAL contains a couple of checks, namely PyString_CheckExact() and hash != -1. We might be able to prove in advance that these two conditions are always true. We could then remove the checks. Not sure the difference measurable, though. ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-12 08:50 Message: Logged In: YES user_id=1424288 Well, why fix it for eval but not for exec? I don't think the time hit is noticeable, I ran 'time make test' twice each on the trunk with and without the patch. Here are the results: Trunk: real 9m17.117s user 3m30.930s sys 0m35.417s real 9m9.471s user 3m31.484s sys 0m34.978s Patch: real 9m32.469s user 3m40.134s sys 0m36.140s real 9m6.779s user 3m27.529s sys 0m34.716s ---------------------------------------------------------------------- Comment By: Martin v. Löwis (loewis) Date: 2006-01-12 07:11 Message: Logged In: YES user_id=21627 I think the history is this: it originates from python.org/sf/215126, which requested that you can pass dict subtypes to eval. Armin noted that eval will always produce LOAD/STORE_NAME, so just modifying these opcodes is sufficient to fulfil the feature request. ---------------------------------------------------------------------- Comment By: Raymond Hettinger (rhettinger) Date: 2006-01-12 02:21 Message: Logged In: YES user_id=80475 Okay, I will take it under consideration. Also, I'll try to remember the reason it wasn't done the first time around. No promises though -- by itself consistency is a weak motivation. ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-12 00:11 Message: Logged In: YES user_id=1424288 Here's a more interesting example. This works fine, unless the variables fall through to the global dictionary, or some code marks them global. import code class ManagedVariable: def get(self): return None def set(self, value): pass def delete(self): # Return false to stop the delete. return True class ManagedEnvironment(dict): def __setitem__(self, key, value): if self.has_key(key): if isinstance(dict.__getitem__(self, key), ManagedVariable): dict.__getitem__(self, key).set(value) return dict.__setitem__(self, key, value) def __getitem__(self, key): if self.has_key(key): if isinstance(dict.__getitem__(self, key), ManagedVariable): return dict.__getitem__(self, key).get() return dict.__getitem__(self, key) def __delitem__(self, key): if self.has_key(key): if isinstance(dict.__getitem__(self, key), ManagedVariable): if not dict.__getitem__(self, key).delete(): return dict.__delitem__(self, key) class RangedInt(ManagedVariable): def __init__(self, value, (low, high)): self.value = value self.low = low self.high = high def get(self): return self.value def set(self, value): if value < self.low: value = self.low if value > self.high: value = self.high self.value = value class FunctionValue(ManagedVariable): def __init__(self, get_func = None, set_func = None, del_func = None): self.get_func = get_func self.set_func = set_func self.del_func = del_func def get(self): if self.get_func: return self.get_func() return None def set(self, value): if self.set_func: self.set_func(value) def delete(self): if self.del_func: return self.del_func() return True class Constant(ManagedVariable): def __init__(self, value): self.value = value def get(self): return self.value def delete(self): return False import time d = ManagedEnvironment() d['ranged'] = RangedInt(1, (0, 100)) d['time'] = FunctionValue(lambda: time.time()) d['constant'] = Constant(42) code.interact(local=d) ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-11 19:12 Message: Logged In: YES user_id=1424288 Here's an example of a little typed environment. It's not the most robust, but it gets you thinking. import code class TypedDictionary(dict): def __setitem__(self, key, value): if self.has_key(key): t = type(self[key]) if t != type(value): try: value = t(value) except Exception: raise TypeError, \ "illegal assignment to '%s':" \ " %s cannot be coerced to %s" \ % (key, type(value), t) dict.__setitem__(self, key, value) code.interact(local=TypedDictionary()) ---------------------------------------------------------------------- Comment By: crutcher (crutcher_gmail) Date: 2006-01-11 03:16 Message: Logged In: YES user_id=1424288 With the ability to use dictionary subclasses for local and global environments, it becomes very easy to implement execution environments with extended variable semantics for special purposes. This includes driving interactive processes, config file processors, type checking, lazy object construction, and read-only variables. As it currently stands, the semantics are inconsistent. The local case should not have been changed if the global case was not going to be changed. ---------------------------------------------------------------------- Comment By: Raymond Hettinger (rhettinger) Date: 2006-01-11 03:03 Message: Logged In: YES user_id=80475 Do you have any use cases? AFAICT, there were no unmet needs with locals option. Also, there was a reason that globals weren't included but I remember what it was. ---------------------------------------------------------------------- You can respond by visiting: https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1402289&group_id=5470 _______________________________________________ Patches mailing list Patches@python.org http://mail.python.org/mailman/listinfo/patches