]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- [bug] implemented standard "can't set attribute" /
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 28 Jan 2012 01:59:33 +0000 (20:59 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 28 Jan 2012 01:59:33 +0000 (20:59 -0500)
"can't delete attribute" AttributeError when
setattr/delattr used on a hybrid that doesn't
define fset or fdel. [ticket:2353]

CHANGES
lib/sqlalchemy/ext/hybrid.py
test/ext/test_hybrid.py

diff --git a/CHANGES b/CHANGES
index 1859b91459be0378ba4198497bd14812a8937c03..bab93885c3586218e353cb4a4e7c323a491f35bd 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -52,6 +52,11 @@ CHANGES
   - [bug] ensure pickleability of all ORM exceptions
     for multiprocessing compatibility. [ticket:2371]
 
+  - [bug] implemented standard "can't set attribute" / 
+    "can't delete attribute" AttributeError when 
+    setattr/delattr used on a hybrid that doesn't 
+    define fset or fdel. [ticket:2353]
+
 - sql
   - [feature] Added "false()" and "true()" expression
     constructs to sqlalchemy.sql namespace, though
index fc09c172dfd82b1ecfc50650dbe46e5a3147895c..086ec90336794b822d959306fa765e4b6c7a86f1 100644 (file)
@@ -613,9 +613,13 @@ class hybrid_property(object):
             return self.fget(instance)
 
     def __set__(self, instance, value):
+        if self.fset is None:
+            raise AttributeError("can't set attribute")
         self.fset(instance, value)
 
     def __delete__(self, instance):
+        if self.fdel is None:
+            raise AttributeError("can't delete attribute")
         self.fdel(instance)
 
     def setter(self, fset):
index 7ed8e207c3b42786e1a4bac4093e940ddc168f56..b85d4b0fc2f0785348db263b016985a7cf7493fe 100644 (file)
@@ -3,7 +3,7 @@ from sqlalchemy.orm import relationship, Session, aliased
 from test.lib.schema import Column
 from sqlalchemy.ext.declarative import declarative_base
 from sqlalchemy.ext import hybrid
-from test.lib.testing import eq_, AssertsCompiledSQL
+from test.lib.testing import eq_, AssertsCompiledSQL, assert_raises_message
 from test.lib import fixtures
 
 class PropertyComparatorTest(fixtures.TestBase, AssertsCompiledSQL):
@@ -191,7 +191,7 @@ class PropertyExpressionTest(fixtures.TestBase, AssertsCompiledSQL):
 
 class PropertyValueTest(fixtures.TestBase, AssertsCompiledSQL):
     __dialect__ = 'default'
-    def _fixture(self):
+    def _fixture(self, assignable):
         Base = declarative_base()
 
         class A(Base):
@@ -203,14 +203,34 @@ class PropertyValueTest(fixtures.TestBase, AssertsCompiledSQL):
             def value(self):
                 return self._value - 5
 
-            @value.setter
-            def value(self, v):
-                self._value = v + 5
+            if assignable:
+                @value.setter
+                def value(self, v):
+                    self._value = v + 5
 
         return A
 
+    def test_nonassignable(self):
+        A = self._fixture(False)
+        a1 = A(_value=5)
+        assert_raises_message(
+            AttributeError, 
+            "can't set attribute",
+            setattr, a1, 'value', 10
+        )
+
+    def test_nondeletable(self):
+        A = self._fixture(False)
+        a1 = A(_value=5)
+        assert_raises_message(
+            AttributeError, 
+            "can't delete attribute",
+            delattr, a1, 'value'
+        )
+
+
     def test_set_get(self):
-        A = self._fixture()
+        A = self._fixture(True)
         a1 = A(value=5)
         eq_(a1.value, 5)
         eq_(a1._value, 10)