aboutsummaryrefslogtreecommitdiffstats
path: root/libbe/properties.py
diff options
context:
space:
mode:
authorW. Trevor King <wking@drexel.edu>2009-06-23 11:35:23 -0400
committerW. Trevor King <wking@drexel.edu>2009-06-23 11:35:23 -0400
commit83e06581ad007e1a1f27f311ccb3a747f0a81ade (patch)
treeda64348e2f7a638e6f0664d5277aa24f1500e3c5 /libbe/properties.py
parent37195a33108299504f8d37042dec06df0540d0d2 (diff)
downloadbugseverywhere-83e06581ad007e1a1f27f311ccb3a747f0a81ade.tar.gz
Added Bug.extra_strings to support add-on functionality, e.g. `be tag`.
Versioned properties whose data is a mutable type are tricky, since the simple comparisons we'd been using in libbe.properties.change_hook_property don't work for mutables. For now, we avoid that problem by assuming a change happened whenever a mutable property is set. change_hook_property is a bit untidy at the moment while I work out how to deal with mutables. As an example of using Bug.extra_strings to patch on some useful functionality, I've written becommands/tag.py. I'd suggest future add-ons (e.g. becommands/depend.py?) use the "<LABEL>:<value>" string format to keep it easy to sort out which strings belong to which add-ons. tag.py is still missing command line tag-removal and tag-searching for `be list'. Perhaps something like be list --extra-strings TAG:<your-tag>,TAG:<another-tag>,DEPEND:<bug-id> would be good, although it would requre escaping commas from the tags, or refusing to allow commas in the tags... libbe.properties.ValueCheckError also got a minor update so the printed error message makes sense when raised with allowed being an iterable (i.e. check_property) or a function (e.g. fn_checked_property). All of this digging around turned up a really buggy libbe.bugdir.MultipleBugMatches. Obviously I had never actually called it before :p. Should be fixed now. libbe.comment._set_comment_body has also been normalized to match the suggested change_hook interface: change_hook(self, old, new). Although, I'm not sure why it hadn't been causing obvious problems before, so maybe I'm misunderstanding something about that.
Diffstat (limited to 'libbe/properties.py')
-rw-r--r--libbe/properties.py44
1 files changed, 39 insertions, 5 deletions
diff --git a/libbe/properties.py b/libbe/properties.py
index a8e89fb..9292ad7 100644
--- a/libbe/properties.py
+++ b/libbe/properties.py
@@ -26,12 +26,15 @@ and
for more information on decorators.
"""
+import types
import unittest
-
class ValueCheckError (ValueError):
def __init__(self, name, value, allowed):
- msg = "%s not in %s for %s" % (value, allowed, name)
+ action = "in" # some list of allowed values
+ if type(allowed) == types.FunctionType:
+ action = "allowed by" # some allowed-value check function
+ msg = "%s not %s %s for %s" % (value, action, allowed, name)
ValueError.__init__(self, msg)
self.name = name
self.value = value
@@ -258,12 +261,29 @@ def primed_property(primer, initVal=None):
return funcs
return decorator
-def change_hook_property(hook):
+def change_hook_property(hook, mutable=False):
"""
Call the function hook(instance, old_value, new_value) whenever a
value different from the current value is set (instance is a a
reference to the class instance to which this property belongs).
- This is useful for saving changes to disk, etc.
+ This is useful for saving changes to disk, etc. This function is
+ called _after_ the new value has been stored, allowing you to
+ change the stored value if you want.
+
+ If mutable=True, store a string-representation of the old_value
+ for use in comparisions, since
+
+ >>> a = []
+ >>> b = a
+ >>> b.append(1)
+ >>> a
+ [1]
+ >>> a==b
+ True
+
+ The string-value-changed test may miss the first write, since
+ there will not have been an opportunity to cache a string version
+ of the old value.
"""
def decorator(funcs):
if hasattr(funcs, "__call__"):
@@ -273,9 +293,23 @@ def change_hook_property(hook):
name = funcs.get("name", "<unknown>")
def _fset(self, value):
old_value = fget(self)
+ fset(self, value)
+ change_detected = False
if value != old_value:
+ change_detected = True
+ elif mutable == True:
+ if True: #hasattr(self, "_change_hook_property_mutable_cache_%s" % name):
+ # compare cached string with new value
+ #old_string = getattr(self, "_change_hook_property_mutable_cache_%s" % name)
+ old_string = "dummy"
+ #print "comparing", name, "mutable strings", old_string, repr(value)
+ if repr(value) != old_string:
+ change_detected = True
+ #print "testing", name, "change hook property", change_detected, value
+ if change_detected:
hook(self, old_value, value)
- fset(self, value)
+ if mutable == True: # cache the new value for next time
+ setattr(self, "_change_hook_property_mutable_cache_%s" % name, repr(value))
funcs["fset"] = _fset
return funcs
return decorator