Introduction to Axiom

Object-Relational Storage for Python

presented by:Cary Hull (cary.hull@gmail.com)

Overview

Pros

Cons

Stores

Persistent containers for:
  • Python objects
  • files
  • Other Stores (SubStores)

Stores cont.

>>> from axiom import store
>>> inmem_s = store.Store()
>>> fs_s = store.Store('users.ax')
>>> fs_s
<Store FilePath('/Users/chull/project/users.ax')

Stores cont.

>>> fs_s.dbdir
FilePath('/Users/chull/project/users.ax')
>>> fs_s.dbdir.path
'/Users/chull/project/users.ax'
>>> fs_s.dbdir.listdir()
['db.sqlite', 'files', 'run', 'temp']

Items

Items cont.

>>> from axiom import item
>>> from axiom import attributes

>>> class User(item.Item):
...     name = attributes.text()
...     age = attributes.integer()
...     homedir = attributes.path()
...

>>> bob = User(store=fs_s, name=u'Bob', age=20)
>>> bob.name, bob.age, bob.storeID
(u'Bob', 20, 1)

>>> alice = User(store=fs_s, name=u'Alice', age=22)
>>> alice.name, alice.age, alice.storeID
(u'Alice', 22, 2)

Attributes

>>> class Song(item.Item):
...     title = attributes.text()
...     data = attributes.bytes()
...     published = attributes.boolean(default=False)
...     price = attributes.money()
...     author = attributes.reference()
...     uploaded_at = attributes.timestamp()
...
>>> bird = Song(store=fs_s, title=u'Bird')

Attributes cont.

>>> bird.name, bird.published, bird.storeID
(u'Bird', False, 3)

Attributes: timestamp

>>> from epsilon import extime
>>> time = extime.Time()
>>> time
extime.Time.fromDatetime(datetime.datetime(2008, 2, 13, 18, 51, 50, 497863))
>>> bird.uploaded_at = time
>>> bird.uploaded_at
extime.Time.fromDatetime(datetime.datetime(2008, 2, 13, 18, 51, 50, 497863))

Attributes: reference

>>> bird.author = bob
>>> bird.author
User(age=20, homedir=None, name=u'Bob', storeID=1)

Queries

>>> for u in fs_s.query(User):
...     print "Found:", u
...
Found: User(age=20, homedir=None, name=u'Bob', storeID=1)
Found: User(age=22, homedir=None, name=u'Alice', storeID=2)

Queries cont(2).

>>> of_age = fs_s.query(User, User.age > 21)
>>> of_age.__class__
<class axiom.store.ItemQuery at 0x1592120>

>>> for u in of_age:
...     print "Over 21:", u
...
Over 21: User(age=22, homedir=None, name=u'Alice', storeID=2)

>>> of_age.count()
1

Queries cont(3).

>>> carol = User(store=fs_s, name=u'Carol', age=34)

>>> for u in of_age:
...     print "Over 21:", u
...
Over 21: User(age=22, homedir=None, name=u'Alice', storeID=2)
Over 21: User(age=34, homedir=None, name=u'Carol', storeID=4)

>>> of_age.count()
2

Queries cont(4).

>>> fs_s.sum(User.age)
76

>>> fs_s.count(User)
3
>>> fs_s.count(User, User.age > 21)
2

Queries cont(5).

>>> fs_s.findUnique(User, User.age == 23)
User(age=22, homedir=None, name=u'Alice', storeID=2)

>>> fs_s.findUnique(User, User.age == 24)
Traceback (most recent call last):
 ...
axiom.errors.ItemNotFound: __main__.User.age = 24

>>> fs_s.findFirst(User)
User(age=20, homedir=None, name=u'Bob', storeID=1)

Comparisons

>>> c_age_over_21 = User.age > 21
>>> c_age_over_21
__main__.User.age > 21
>>> type(c_age_over_21)
<class 'axiom.attributes.AttributeValueComparison'>

Comparisons cont(2).

>>> c_free_songs_by_bob = attributes.AND(
...     Song.author == bob,
...     Song.price == None
...     )
>>> c_free_songs_by_bob
AND(__main__.Song.author = User(age=20, homedir=None, name=u'bob', storeID=1), <axiom.attributes.NullComparison object at 0x1570330>)

>>> q_free_songs = fs_s.query(Song, c_free_songs_by_bob)
>>> for s in q_free_songs:
...     print "Found:", s
...
Found: Song(author=reference(1), data=None, price=None, published=False, title=u'Bird', uploaded_at=None, storeID=3)

Comparisons cont(3).

>>> dog = Song(store=fs_s, author=bob, title=u'Dog')

>>> for s in q_free_songs:
...     print "Found:", s.title
...
Found: Bird
Found: Dog

Comparisons cont(4).

>>> dog.price = 1

>>> for s in q_free_songs:
...     print "Found:", s.title
...
Found: Bird

Powerups

>>> import zope.interface as zi

>>> class IHtmlFragment(zi.Interface):
...     """An HTML fragment"""
...     def Render():
...         """Returns an HTML fragment representing adapted object"""
...

Powerups cont(2).

>>> from axiom import dependency

>>> class SpecialUserHtml(item.Item):
...     zi.implements(IHtmlFragment)
...     powerupInterfaces = [IHtmlFragment]
...     css_classes = attributes.textlist()
...     def Render(self):
...         user = dependency.installedOn(self)
...         classes = ' '.join(self.css_classes)
...         return '<div class="user %s"><h1>%s</h1></div>' % (classes, user.name)
...

Powerups cont(3).

>>> userfrag = SpecialUserHtml(store=fs_s, css_classes=['greenish'])
>>> dependency.installOn(userfrag, bob)

>>> IHtmlFragment(bob).Render()
u'<div class="user greenish"><h1>bob</h1></div>'

SubStores

>>> from axiom import substore
>>> sub1 = substore.SubStore.createNew(fs_s, ['first_sub'])
>>> sub1
SubStore(storepath=FilePath('/Users/chull/project/users.ax/files/first_sub'), storeID=6)
>>> sub1_s = sub1.open()
>>> sub1_s
<Store FilePath('/Users/chull/project/users.ax/files/first_sub')>

SubStores cont.

>>> claude = User(store=sub1_s, name=u'Claude', age=30)
>>> dog.author = claude
Traceback (most recent call last):
 ...
axiom.errors.NoCrossStoreReferences: You can't establish references to items in other stores.

File Storage

>>> homedir = fs_s.newDirectory('bob')
>>> homedir
FilePath('/Users/chull/project/users.ax/files/bob')

File Storage cont(2).

>>> bob.homedir = homedir
>>> bob.homedir
FilePath('/Users/chull/project/users.ax/files/bob')