rdfList with complex objects

6 views
Skip to first unread message

Corydodt

unread,
Jun 16, 2009, 2:09:55 AM6/16/09
to rdfalchemy-dev
Hi again list,

I'm trying to make a list containing typed bnodes work.

I started with this N3: (WORKS - but not what I want)

:bob a :Monster; :name "bob";
:attack [ a :Attack; rdf:value 20 ],
[ a :Attack; rdf:value 21; rdfs:comment "plus
poison" ],
[ a :Attack; rdf:value 22 ] .

I can write:

class Attack(S.rdfsPTClass):
rdf_type = FUN.Attack
value = rdfList(RDF.value)

class Monster(S.rdfsPTClass):
name = rdfSingle(FUN.name)
attack = rdfMultiple(FUN.attack, range_type=FUN.Attack)

and everything is fine, I can access monster.attack[0].value and get
21, for
example.

This list really represents three arcs:

:bob :attack ATTACK20. :bob :attack ATTACK21. :bob :attack
ATTACK22.

However, order is undefined here, and I need ATTACK20 to be first, so
here's
the N3 I decided to write instead (with a sneaking suspicion that it
was
going to give me trouble in rdfalchemy):

What I really want - but DOESN'T WORK:

:bob a :Monster; :name "bob";
:attack ( [ a :Attack; rdf:value 20 ],
[ a :Attack; rdf:value 21; rdfs:comment "plus
poison" ],
[ a :Attack; rdf:value 22 ] ) .

Now :attack has a single object, a list. This change is needed to the
Monster
class to be able to load :bob the Monster:

class Monster(S.rdfsPTClass):
name = rdfSingle(FUN.name)
attack = rdfList(FUN.attack, range_type=FUN.Attack)

Now I can't access monster.attack[0].value any more. The error I get
is

AttributeError: 'rdfSubject' object has no attribute 'value'

I suspect this is because range_type is supposed to refer to the
*single
object* of :attack, and that object is a list, not an :Attack, so
range_type
isn't helping me any more. The list shows up as a generic rdfSubject,
unmapped.

Is there some way I can do this by adding another class? (Subclass
rdfList
perhaps? That seems like overkill!) Is there some way I can modify
Monster
so that monster.attack[0].value is what I want it to be?

Thanks!

C

Philip Cooper

unread,
Jun 17, 2009, 3:34:52 PM6/17/09
to rdfalch...@googlegroups.com
On Jun 16, 2009, at 12:09 AM, Corydodt wrote:


Hi again list,

I'm trying to make a list containing typed bnodes work.

I started with this N3: (WORKS - but not what I want)

<looks ok ...>


However, order is undefined here,

Right Multiple triples with the same subject,predicate come back unordered

and I need ATTACK20 to be first, so
here's
the N3 I decided to write instead (with a sneaking suspicion that it
was going to give me trouble in rdfalchemy):

What I really want - but DOESN'T WORK:

   :bob a :Monster; :name "bob";
       :attack ( [ a :Attack; rdf:value 20 ],
                 [ a :Attack; rdf:value 21; rdfs:comment "plus
poison" ],
                 [ a :Attack; rdf:value 22 ] ) .

Now :attack has a single object, a list.  This change is needed to the
Monster
class to be able to load :bob the Monster:

   class Monster(S.rdfsPTClass):
       name = rdfSingle(FUN.name)
       attack = rdfList(FUN.attack, range_type=FUN.Attack)

Now I can't access monster.attack[0].value any more.  The error I get
is

Need to change the n3.  
Multiple objects for the same s,p pair are comma seperated. 
A list is a list of space seperated values.  

Try n3 of:
######################################

:bob a :Monster; 
    :name "bob";
    :attack ( [ a :Attack; rdf:value 20 ]
              [ a :Attack; rdf:value 21; 
                           rdfs:comment "plus poison" ] 
              [ a :Attack; rdf:value 22 ] )  .
######################################
I suspect this is because range_type is supposed to refer to the
*single
object* of :attack, and that object is a list, not an :Attack, so
range_type isn't helping me any more.  

The list shows up as a generic rdfSubject,
unmapped.

Need to run the rdfalchemy.orm.mapper() method to get it mapped
Think the Monster predicate refers to a list of Attacks (attack value should be a single not a list)


so that monster.attack[0].value is what I want it to be?

Right try something like:
######################################
from rdfalchemy import *
from rdfalchemy.orm import mapper
FUN = Namespace('http://cory.com/FUN#')

class Attack(rdfSubject):
   rdf_type = FUN.Attack
   value = rdfSingle(RDF.value)

class Monster(rdfSubject):
   name = rdfSingle(FUN.name)
   attack = rdfList(FUN.attack, range_type=FUN.Attack)

mapper()

rdfSubject.db.load('<the n3 file above>',format='n3')
m = Monster.ClassInstances().next()

print "First attack val: %s"% m.attack[0].value
print "Second attack "
m.attack[1]._ppo()
######################################

I think this returns everything as you expected.

BTW, in the current dev trunk I've added rdfsSubject as a smarter rdfSubject.

The code above works with rdfSubject but if you get to the point where you
subclass Attack and want to have  monster.attack return a list of the correct subclasses
you can actually do that.

Also, for a Virtual world type app like your samples imply, rdfsSubject also 
uses weakref's to make sure that there is only one instance of a given monster
defined in your running app.

More on these updates as I roll them into the "public" i.e. cheeseshop, release of rdfalchemy.

--
Phil

Cory Dodt

unread,
Jun 19, 2009, 2:24:35 AM6/19/09
to rdfalch...@googlegroups.com
Thanks!

It seems that this works, but only with a very recent SVN trunk.  I was actually working with a 0.2b2 rdfalchemy from svn trunk, the one currently tarballed at http://goonmill.org/static/RDFAlchemy-0.2b2.svn1.tar.gz .  This was a version of your code I pulled after you added rdfsSubject, because I started using that right off the bat :-)  (I tarred it up because it is the only sane way to include it in a setup.py dependency.  I certainly hope you will do another cheeseshop update! :-)

That snapshot did not work with the code I had posted - until now.  Since updating again, the original code now works and allows me to get Attack objects, not generics.  I'll update my snapshot and dependencies for now.


Related to this, I have a bug report.  Using rdfsSubject now gives me this message:

No handlers could be found for logger "rdfalchemy.rdfsSubject"

This is unconditionally written to stderr.

C
--
_____________________
Reply all
Reply to author
Forward
0 new messages