Commits

Mike Bayer committed d621e47

- mapped classes which extend "object" and do not provide an
__init__() method will now raise TypeError if non-empty *args
or **kwargs are present at instance construction time (and are
not consumed by any extensions such as the scoped_session mapper),
consistent with the behavior of normal Python classes [ticket:908]

Comments (0)

Files changed (7)

      
    - columns which are missing from a Query's select statement
      now get automatically deferred during load.
-   
+
+   - mapped classes which extend "object" and do not provide an 
+     __init__() method will now raise TypeError if non-empty *args 
+     or **kwargs are present at instance construction time (and are 
+     not consumed by any extensions such as the scoped_session mapper), 
+     consistent with the behavior of normal Python classes [ticket:908]
+     
    - fixed Query bug when filter_by() compares a relation against None
      [ticket:899]
      

lib/sqlalchemy/orm/attributes.py

         if extra_init:
             extra_init(class_, oldinit, instance, args, kwargs)
 
-        if doinit:
-            try:
+        try:
+            if doinit:
                 oldinit(instance, *args, **kwargs)
-            except:
-                if on_exception:
-                    on_exception(class_, oldinit, instance, args, kwargs)
-                raise
-    
+            elif args or kwargs:
+                # simulate error message raised by object(), but don't copy
+                # the text verbatim
+                raise TypeError("default constructor for object() takes no parameters")
+        except:
+            if on_exception:
+                on_exception(class_, oldinit, instance, args, kwargs)
+            raise
+                
+            
     # override oldinit
     oldinit = class_.__init__
     if oldinit is None or not hasattr(oldinit, '_oldinit'):

lib/sqlalchemy/orm/scoping.py

             class_.query = query()
         
     def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
+        if self.save_on_init:
+            entity_name = kwargs.pop('_sa_entity_name', None)
+            session = kwargs.pop('_sa_session', None)
         if not isinstance(oldinit, types.MethodType):
             for key, value in kwargs.items():
                 if self.validate:
                     if not mapper.get_property(key, resolve_synonyms=False, raiseerr=False):
                         raise exceptions.ArgumentError("Invalid __init__ argument: '%s'" % key)
                 setattr(instance, key, value)
+            kwargs.clear()
         if self.save_on_init:
-            session = kwargs.pop('_sa_session', self.context.registry())
-            session._save_impl(instance, entity_name=kwargs.pop('_sa_entity_name', None))
+            session = session or self.context.registry()
+            session._save_impl(instance, entity_name=entity_name)
         return EXT_CONTINUE
 
     def init_failed(self, mapper, class_, oldinit, instance, args, kwargs):

test/orm/inheritance/basic.py

         )
         admin_mapper = mapper(Admin, admins, inherits=user_mapper)
         sess = create_session()
-        adminrole = Role('admin')
+        adminrole = Role()
         sess.save(adminrole)
         sess.flush()
 

test/orm/inheritance/manytomany.py

             Column('bar_id', Integer, ForeignKey('bar.bid')))
 
     def testget(self):
-        class Foo(object):pass
-        def __init__(self, data=None):
-            self.data = data
+        class Foo(object):
+            def __init__(self, data=None):
+                self.data = data
         class Bar(Foo):pass
 
         mapper(Foo, foo)
         sess.flush()
         sess.clear()
 
-        l = sess.query(Bar).select()
+        l = sess.query(Bar).all()
         print l[0]
         print l[0].foos
         self.assert_unordered_result(l, Bar,
         sess.flush()
         compare = repr(b) + repr(sorted([repr(o) for o in b.foos]))
         sess.clear()
-        l = sess.query(Bar).select()
+        l = sess.query(Bar).all()
         print repr(l[0]) + repr(l[0].foos)
         found = repr(l[0]) + repr(sorted([repr(o) for o in l[0].foos]))
         self.assertEqual(found, compare)
         blubid = bl1.id
         sess.clear()
 
-        l = sess.query(Blub).select()
+        l = sess.query(Blub).all()
         print l
         self.assert_(repr(l[0]) == compare)
         sess.clear()
-        x = sess.query(Blub).get_by(id=blubid)
+        x = sess.query(Blub).filter_by(id=blubid).one()
         print x
         self.assert_(repr(x) == compare)
 

test/orm/mapper.py

         except Exception, e:
             assert e is ex
 
+        clear_mappers()
+        
+        # test that TypeError is raised for illegal constructor args,
+        # whether or not explicit __init__ is present [ticket:908]
+        class Foo(object):
+            def __init__(self):
+                pass
+        class Bar(object):
+            pass
+                
+        mapper(Foo, users)
+        mapper(Bar, addresses)
+        try:
+            Foo(x=5)
+            assert False
+        except TypeError:
+            assert True
+
+        try:
+            Bar(x=5)
+            assert False
+        except TypeError:
+            assert True
+
     def test_props(self):
         m = mapper(User, users, properties = {
             'addresses' : relation(mapper(Address, addresses))
         
         sess = create_session()
         i1 = Item()
-        k1 = Keyword('blue')
+        k1 = Keyword()
         sess.save(i1)
         sess.save(k1)
         sess.flush()

test/orm/session.py

             pass
         Session.mapper(Baz, table2, extension=ext)
         assert hasattr(Baz, 'query')
-
+    
     def test_validating_constructor(self):
         s2 = SomeObject(someid=12)
         s3 = SomeOtherObject(someid=123, bogus=345)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.