le 25.06.2007 17:15 Gaetan de Menten a écrit:
> On 6/25/07, remi jolin <[EMAIL PROTECTED]> wrote:
>   
>> le 23.06.2007 00:00 Gaetan de Menten a écrit:
>>     
>>> This is a (known) bug in Elixir. The cause is that we don't setup
>>> backrefs as we should.
>>>
>>> As I said to André Felipe Dias:
>>> ======
>>> Feel free to work on a patch, though I'm not sure how hard it would
>>> be. Basically, when a relationship has an inverse, it must setup a
>>> backref. The catch is that you must catch all the arguments of the
>>> inverse relationship and pass them through to the backref.
>>> ======
>>>
>>>       
>> Gaetan,
>>
>> I made a (simple) patch and a test for backrefs. It seems to work (at
>> least as I expect it to work ;-)  )
>>     
>
> Great news!
>
>   
>> I also found an issue in the test_multi.py test but I think it is a bug
>> in the test (I've corrected it  also).
>>     
>
> I'll see about that.
>
>   
>> The only test that does not pass is test_has_property but I think it
>> because my version of sqlalchemy is too old (0.3.6) "ImportError: cannot
>> import name column_property"
>>     
>
> Indeed.
>
>   
>> How can we get further ?
>>     
>
> Please send the patch here and I'll have a look at it and commit it if
> it's good enough and otherwise tell you what's wrong.
>
>   
Here are all the patchs and the new test.
As you see, the patch is very simple but seems to do the work...

Index: elixir/relationships.py
===================================================================
--- elixir/relationships.py     (révision 135)
+++ elixir/relationships.py     (copie de travail)
@@ -329,6 +329,8 @@
                (self.inverse_name == other.name or not 
self.inverse_name) and \                (other.inverse_name == self.name 
or not other.inverse_name)

+    def __repr__(self):
+        return "<%s name:%s>" % (self.__class__.__name__, self.name)

 class BelongsTo(Relationship):
     '''
@@ -447,7 +449,10 @@
         if self.primaryjoin_clauses:
             kwargs['primaryjoin'] = and_(*self.primaryjoin_clauses)
         kwargs['uselist'] = False
-
+
+        if self.inverse:
+            kwargs['backref'] = self.inverse.name
+
         self.property = relation(self.target, **kwargs)
         self.entity.mapper.add_property(self.name, self.property)

@@ -487,6 +492,7 @@
             kwargs['primaryjoin'] = and_(*self.inverse.primaryjoin_clauses)

         kwargs['uselist'] = self.uselist
+        kwargs['backref'] = self.inverse.name

         self.property = relation(self.target, **kwargs)
         self.entity.mapper.add_property(self.name, self.property)
@@ -660,6 +666,9 @@
             kwargs['order_by'] = \
                 
self.target._descriptor.translate_order_by(kwargs['order_by'])

+        if self.inverse:
+            kwargs['backref'] = self.inverse.name
+
         self.property = relation(self.target, 
secondary=self.secondary_table,
                                  uselist=True, **kwargs)
         self.entity.mapper.add_property(self.name, self.property)

-------------------------------
Index: tests/test_multi.py
===================================================================
--- tests/test_multi.py (révision 135)
+++ tests/test_multi.py (copie de travail)
@@ -52,7 +52,8 @@

         homer = Person.get_by(name="Homer")
         lisa = Person.get_by(name="Lisa")
-
+        slh = Animal.get_by(name="Santa's Little Helper")
+
         print homer

         assert len(homer.animals) == 2
-----------------------
The problem here is that after the objectstore.clear(), slh contained 
some "zombi" datas, not something from the database... Perharps, we 
should separate in 2 different functions the load of the database (up to 
objectstore.clear() and the requests so we get sure that a var doesn't 
keep an unrelevant data...
Same issue with test_autoload.py.

Index: tests/test_autoload.py
===================================================================
--- tests/test_autoload.py      (révision 135)
+++ tests/test_autoload.py      (copie de travail)
@@ -101,7 +101,8 @@

         homer = Person.get_by(name="Homer")
         lisa = Person.get_by(name="Lisa")
-
+        slh = Animal.get_by(name="Santa's Little Helper")
+
         print homer

         assert len(homer.animals) == 2
------------------------------------
tests/test_backref.py (new test...)

"""
    simple test case for backrefs
"""

import sqlalchemy
from elixir import *

#-----------

class TestMultiBelongsTo(object):
    def setup(self):
        global Person, Animal

        #---------------------------------------
        # classes for the multi belongs_to test

        class Person(Entity):
            has_field('name', Unicode(32))

            has_many('pets', of_kind='Animal', inverse='owner')
            has_many('animals', of_kind='Animal', inverse='feeder')

            def __str__(self):
                s = '%s\n' % self.name.encode('utf-8')
                for pet in self.pets:
                    s += '  * pet: %s\n' % pet.name
                return s

        class Animal(Entity):
            has_field('name', String(15))
            has_field('color', String(15))

            belongs_to('owner', of_kind='Person')
            belongs_to('feeder', of_kind='Person')

        engine = sqlalchemy.create_engine('sqlite:///')
        metadata.connect(engine)
        create_all()

    def teardown(self):
        cleanup_all()
        objectstore.clear()

    def test_belongs_to_multi_ref(self):
        snowball = Animal(name="Snowball II", color="grey")
        slh = Animal(name="Santa's Little Helper")
        homer = Person(name="Homer", animals=[snowball, slh], pets=[slh])
        lisa = Person(name="Lisa", pets=[snowball])

        print homer

        assert lisa == snowball.owner
        assert homer == slh.feeder
        assert homer == lisa.pets[0].feeder
        assert homer == slh.owner

        objectstore.flush()
        objectstore.clear()

        homer = Person.get_by(name="Homer")
        lisa = Person.get_by(name="Lisa")
        slh = Animal.get_by(name="Santa's Little Helper")

        print "homer:", homer
        print "slh.owner:", slh.owner

        assert len(homer.animals) == 2
        assert homer == lisa.pets[0].feeder
        assert homer == slh.owner

class TestMovies(object):
    def setup(self):
        global Director, Movie, Actor, Media

        class Director(Entity):
            with_fields(
                name = Field(Unicode(60))
            )

            has_many('movies', of_kind='Movie', inverse='director')


        class Movie(Entity):
            """
                simple movie class
            """

            # columns
            with_fields(
                title = Field(Unicode(50)),
                year = Field(Integer)
            )

            # relationships
            belongs_to('director', of_kind="Director", inverse='movies')

            has_and_belongs_to_many('actors', of_kind="Actor", 
inverse='movies')            has_one('media', of_kind='Media', 
inverse='movie')


        class Actor(Entity):
            with_fields(
                name = Field(Unicode(60))
            )

            has_and_belongs_to_many('movies', of_kind="Movie", 
inverse="actors")

        class Media(Entity):
            with_fields(
                number = Field(Integer, primary_key=True)
            )

            belongs_to('movie', of_kind='Movie', inverse='media')

        engine = sqlalchemy.create_engine('sqlite:///')
        metadata.connect(engine)
        create_all()

    def teardown(self):
        drop_all()
        objectstore.clear()

    def test_bidirectional(self):
        brunner = Movie(title="Blade Runner", year=1982)
        alien = Movie(title="Alien", year=1979)
        swars = Movie(title="Star Wars", year=1977)

        m1 = Media(number=1)
        brunner.media = m1
        m7 = Media(number=7)
        m7.movie = alien

        rscott = Director(name="Ridley Scott")
        glucas = Director(name="George Lucas")

        hford = Actor(name="Harrison Ford")
        mhamill = Actor(name="Mark Hamill")
        sweaver = Actor(name="Sigourney Weaver")

        rscott.movies.append(brunner)
        rscott.movies.append(alien)
        swars.director = glucas

        swars.actors.append(hford)
        swars.actors.append(mhamill)
        alien.actors.append(sweaver)
        brunner.actors.append(hford)

        # directors
        assert rscott == brunner.director
        assert rscott == alien.director
        assert swars in glucas.movies

        # actors
        assert swars in hford.movies
        assert swars in mhamill.movies
        assert alien in sweaver.movies
        assert brunner in hford.movies
        assert len(hford.movies) == 2

        # media
        assert alien.media == m7
        assert m1.movie == brunner


if __name__ == '__main__':
    test = TestMultiBelongsTo()
    test.setup()
    test.test_belongs_to_multi_ref()
    test.teardown()

    test = TestMovies()
    test.setup()
    test.test_bidirectional()
    test.teardown()


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"SQLElixir" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlelixir?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to