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
-~----------~----~----~----~------~----~------~--~---