rdfIsInstance implementation and tests

3 views
Skip to first unread message

Cory Dodt

unread,
Apr 13, 2009, 1:51:29 AM4/13/09
to rdfalch...@googlegroups.com
Passing this along.  The tests are complete except for the fixture TestableDatabase.  You can replace that with any Graph after calling:
    graph.bind(STAFF, '')
... and add the triples in corpN3 to it.

The tests should explain what they're all about, but this is just the implementation of class-as-boolean for rdfalchemy.

######################################################################

corpN3 = """
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<> rdfs:label "Test document - Corporate Staff" .
<> rdfs:comment "So much Enterprise you'll crap yourself!" .

:Employee a rdfs:Class .
:PeoplePerson a rdfs:Class .
:StraightShooterWithUpperManagementWrittenAllOverHim a rdfs:Class .

:e1230 :firstname "Peter";
    :lastname "Gibbons";
    :supervisor :e1001;
    a :Employee;
    a :StraightShooterWithUpperManagementWrittenAllOverHim ;
    :nickname "\"The Gib\"";
    # do _not_ give him a :middlename.  testing defaults.
.

:e1001 :firstname "Bill";
    :lastname "Lumbergh";
    :supervisor :e900;
    a :PeoplePerson;
    a :Employee;
.
"""


class rdfIsInstance(rdfAbstract):
    """
    An rdfalchemy descriptor that makes a boolean out of Bar in this
    construction:

        :Bar a rdfs:Class .
        :foo a :Bar.

    Does *not* check for is-a semantics at this point - just exact boolean
    match on that class.
    """
    def __init__(self, classToCheck):
        self.klass = classToCheck
 
    def __get__(self, obj, cls):
        #code to check for obj a self.klass
        if obj is None:
            return self
        if self.klass in obj.__dict__:
            return obj.__dict__[self.klass]
        qText = "ASK { %s a %s . }" % (obj.n3(), self.klass.n3())
        q = obj.db.query(qText)
        ret = list(q.askAnswer)[0]
        obj.__dict__[self.klass] = ret
        return ret
 
    def __set__(self, obj, true_false):
        """
        Create the triple for obj
        """
        obj.__dict__[self.klass] = true_false
        obj.db.set((obj.resUri, self.klass, true_false))

    def __delete__(self, obj):
        if obj.__dict__.has_key(self.klass):
            del obj.__dict__[self.klass]
            print "DELETED"
        for s,p,o in obj.db.triples((obj.resUri, RDF_a, self.klass)):
            obj.db.remove((s,p,o))

STAFF = Namespace('http://corp.com/staff#')

class Employee2(rdfSubject):
    """
    Employee, using the rdfalchemy ORM
    """
    rdf_type = STAFF.Employee
    firstname = rdfSingle(STAFF.firstname)
    lastname = rdfSingle(STAFF.lastname)
    straightShooter = sparqly.rdfIsInstance(
            STAFF.StraightShooterWithUpperManagementWrittenAllOverHim)
    peoplePerson = sparqly.rdfIsInstance( STAFF.PeoplePerson)
    nickname = rdfSingle(STAFF.nickname)


class RDFAlchemyDescriptorTestCase(unittest.TestCase):
    """
    Tests of the rdfIsInstance descriptor
    """
    def test_basicSchemaCreate(self):
        """
        We can use an in-memory store
        """
        michael = Employee2()
        michael.firstname = "Michael"
        michael.lastname = "Bolton"
        self.assertEqual(michael.lastname, "Bolton")

    def test_basicSchemaAccess(self):
        """
        We can access the data through the sqlalchemy ORM
        """
        db = TestableDatabase()
        db.extendFromFilename(sibpath(__file__, 'corp.n3'))
        rdfSubject.db = db.graph

        peter = Employee2.get_by(lastname='Gibbons')
        self.assertEqual(peter.firstname, 'Peter')
        self.assertEqual(peter.nickname, '"The Gib"')
        peter.nickname = "Gibster"
        self.assertEqual(peter.nickname, 'Gibster')

    def test_readUpdateDescriptor(self):
        """
        Access a rdfIsInstance descriptor that was already specified in n3
        """
        peter = Employee2.get_by(lastname='Gibbons')
        self.assertTrue(peter.straightShooter, "Peter should be a straight shooter")
        peter.straightShooter = False
        self.failIf(peter.straightShooter, "Peter should no longer be a straight shooter")

    def test_createDescriptor(self):
        """
        Create a rdfIsInstance descriptor
        """
        peter = Employee2.get_by(lastname='Gibbons')
        self.assertEqual(peter.peoplePerson, False, "peter.peoplePerson should be False")
        peter.peoplePerson = True
        self.assertTrue(peter.peoplePerson, "Peter should now be a people person")

    def test_deleteDescriptor(self):
        """
        Delete a rdfIsInstance descriptor
        """
        bill = Employee2.get_by(lastname='Lumbergh')
        self.assertTrue(bill.peoplePerson, "bill should be a people person")
        del bill.peoplePerson
        self.failIf(bill.peoplePerson, "bill.peoplePerson should have been deleted")


_____________________

Cory Dodt

unread,
Apr 13, 2009, 2:37:12 AM4/13/09
to rdfalch...@googlegroups.com
One minor modification: I added this to work with mapper().  It is set to None because there's no reason to try to map the type of an rdfIsInstance.

@@ -540,6 +540,8 @@

     Does *not* check for is-a semantics at this point - just exact boolean
     match on that class.
     """
+    range_type = None
+

     def __init__(self, classToCheck):
         self.klass = classToCheck


--
_____________________

Philip Cooper

unread,
Apr 14, 2009, 5:45:43 PM4/14/09
to rdfalch...@googlegroups.com
Cory Dodt wrote:
> Passing this along. .....

> corpN3 = """
> @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
>
> <> rdfs:label "Test document - Corporate Staff" .
> <> rdfs:comment "So much Enterprise you'll crap yourself!" .
>
> :Employee a rdfs:Class .
> :PeoplePerson a rdfs:Class .
> :StraightShooterWithUpperManagementWrittenAllOverHim a rdfs:Class .
>
> :e1230 :firstname "Peter";
> :lastname "Gibbons";
> :supervisor :e1001;
> a :Employee;
> a :StraightShooterWithUpperManagementWrittenAllOverHim ;
> :nickname "\"The Gib\"";
> # do _not_ give him a :middlename. testing defaults.
> .
>

Looking good. Consider using existing vocabularies. Check our FOAF [1]
for people and Dublin Core Relationships [2] for some of the above

[1] http://xmlns.com/foaf/spec/
[2] http://vocab.org/relationship/


>
> def __get__(self, obj, cls):
> #code to check for obj a self.klass
> if obj is None:
> return self
> if self.klass in obj.__dict__:
> return obj.__dict__[self.klass]
> qText = "ASK { %s a %s . }" % (obj.n3(), self.klass.n3())
> q = obj.db.query(qText)
> ret = list(q.askAnswer)[0]
> obj.__dict__[self.klass] = ret
> return ret

rather than constructing an ASK query I would tend to jump to the triple
you are looking for..something like:

ret = list(obj.db.triples((obj,RDF.type,self.klass))) and True or False

Probably faster BUT since the descriptor caches the result in the
obj.__dict__ (well done!) speed is probably not a real problem.

--
Phil

Cory Dodt

unread,
Apr 14, 2009, 6:40:22 PM4/14/09
to rdfalch...@googlegroups.com
On Tue, Apr 14, 2009 at 2:45 PM, Philip Cooper <philip...@openvest.com> wrote:

Cory Dodt wrote:
> Passing this along.  .....
>[..]
Looking good.  Consider using existing vocabularies.  Check our FOAF [1]
for people and Dublin Core Relationships [2] for some of the above

[1] http://xmlns.com/foaf/spec/
[2] http://vocab.org/relationship/

Oh heh, that's all fake.  I just wrote up some n3 so I could have something to run my tests against.  My application doesn't do anything like that. :-)

 
>
>     def __get__(self, obj, cls):
>         #code to check for obj a self.klass
>         if obj is None:
>             return self
>         if self.klass in obj.__dict__:
>             return obj.__dict__[self.klass]
>         qText = "ASK { %s a %s . }" % (obj.n3(), self.klass.n3())
>         q = obj.db.query(qText)
>         ret = list(q.askAnswer)[0]
>         obj.__dict__[self.klass] = ret
>         return ret
rather than constructing an ASK query I would tend to jump to the triple
you are looking for..something like:

ret = list(obj.db.triples((obj,RDF.type,self.klass))) and True or False

Probably faster BUT since the descriptor caches the result in the
obj.__dict__ (well done!) speed is probably not a real problem.

Heh, I just copied rdfSingle there, it looked like it would dtrt.  Is any of this useful to rdfalchemy core?

Reply all
Reply to author
Forward
0 new messages