How to create new objects

1 view
Skip to first unread message

erob

unread,
May 6, 2009, 11:20:40 AM5/6/09
to Schevo

Hi,

trying to learn Schevo and the world of object-relational databases,
but how do we simply
create new empty objects using new-style class inheritance ?

i know that i can do things like:

>>> db.Blog[1]

to access the instance object having the oid 1, but im unable to find
the proper way
to create a new instance programmaticaly.

i thought that given the "as_data()" method, i could clone an instance
to a tuple then
use that data for initializing default values:

>>> data = db.Blog[1].as_data()
>>> obj = db.Blog(**data)

or even perhaps "get_or_create" could be implemented as a simple class
method
for creating it:

>>> obj = db.Blog.get_or_create(**data)

any ideas how to accomplish this kind of functionality using Schevo,
or maybe im missing
something obvious ?

Thanks,

erob

Matthew Scott

unread,
May 6, 2009, 12:01:08 PM5/6/09
to sch...@googlegroups.com
Schevo's transaction model is that any changes to the database must occur within a "transaction instance", sometimes just referred to as a "transaction".  Such an object is an instance of a transaction class.

Schevo gives you standard Create, Delete, and Update transaction classes out of the box.

Say you have an extent, db.Blog, based on this entity class:

  class Blog(E.Entity):
      name = f.string()
      _key(name)

To create a new Blog entity programmatically, first get a create transaction from the extent.  Do this by calling the 'create' method that is on the 't' namespace of the extent:

  >>> tx = db.Blog.t.create()

Set the field value(s) for the new Blog on the transaction:

  >>> tx.name = 'New Blog'

Finally, execute the transaction.  The return value is the new entity:

  >>> blog = db.execute(tx)
  >>> blog.name
  u'New Blog'
  >>> blog in db.Blog
  True

Now, you can perform 'update' and 'delete' transactions on the entity:

  >>> tx = blog.t.update()
  >>> tx.name = 'New Name'
  >>> db.execute(tx)
  >>> blog.name
  u'New Name'

  >>> tx = blog.t.delete()
  >>> db.execute(tx)
  >>> blog in db.Blog
  False

Hope this helps!
--
Matthew R. Scott

Etienne Robillard

unread,
May 7, 2009, 1:12:22 PM5/7/09
to Matthew Scott, sch...@googlegroups.com

Okay cool, I seem to have misread that section in the tutorial. :)
Its working nicely. I made a simple "transaction manager" based
on it. I think using class methods would also work, but this seems
sufficient for my blog app..

Kind regards,

Etienne

class TransactionManager(object):
"""Manages create/delete/update transactions

Usage:

>>> m = TransactionManager(db)
>>> tx = m.create('BlogEntry', 5, **data)

"""

def __init__(self, db):
self.db = db

def create(self, name, oid, **kwargs):
"""override this method to customize the create transaction"""
# get the extent using extent(name)
Extent = self.db.extent(name)
tx = Extent[oid].t.create()
# update tx.__dict__ with the data in **kwargs
tx.__dict__.update(**kwargs)
# execute this transaction..
return self.db.execute(tx)

Matthew Scott

unread,
May 7, 2009, 2:49:32 PM5/7/09
to Etienne Robillard, sch...@googlegroups.com
Something to keep in mind is the distinction between extent-level transactions and entity-level transactions.

In your example, you have this line:

    tx = Extent[oid].t.create()

However all you really need to do is to use:

    tx = Extent.t.create()

This is because to create a new entity, you shouldn't need an existing entity, so 'create' is attached to the extent, and it gathers information about the entity class's fields from the extent in which you're creating a new entity.

If you have an existing entity, and you want to create a new entity based on its field values, you'd use 'clone' instead:

    tx = existing_entity.t.clone()
    # ... tx's fields are now the same values as existing_entity's fields ...
    # ... set new field values as needed ...
    clone_of_existing_entity = db.execute(tx)
    

Of note is that transaction methods can receive keyword arguments, which means that you don't have to use your TransactionManager after all:

    tx = db.Blog.t.create(name='My Blog')
    blog = db.execute(tx)

Or, to copy your usage example into a one-liner:

    blog_entry = db.execute(db.BlogEntry.t.create(**data))

Please do not update tx.__dict__ directly.  There are lots of field validation and transformation hooks that go on behind the scenes.  You should either set attributes, or pass in keyword arguments to the transaction method as noted above.


Have fun!


On Thu, May 7, 2009 at 10:12, Etienne Robillard <robillar...@gmail.com> wrote:

Okay cool, I seem to have misread that section in the tutorial. :)
Its working nicely. I made a simple "transaction manager" based
on it. I think using class methods would also work, but this seems
sufficient for my blog app..

Kind regards,

 Etienne

class TransactionManager(object):
   """Manages create/delete/update transactions

   Usage:

   >>> m = TransactionManager(db)
   >>> tx = m.create('BlogEntry', 5, **data)

   """

   def __init__(self, db):
       self.db = db

   def create(self, name, oid, **kwargs):
       """override this method to customize the create transaction"""
       # get the extent using extent(name)
       Extent = self.db.extent(name)
       tx = Extent[oid].t.create()
       # update tx.__dict__ with the data in **kwargs
       tx.__dict__.update(**kwargs)
       # execute this transaction..
       return self.db.execute(tx)


--
Matthew R. Scott

erob

unread,
May 8, 2009, 9:22:18 AM5/8/09
to Schevo

Hi Matthew,

Thanks for your feedback! I appreciate your precious help
learning Schevo on your shoulders... ;-)

Also, how can we create a batch of new entities ?

I was thinking to use some sort of `TransactionQueue' that
could plug in the TransactionManager instance. This way I'm
persuading myself that I can create a list of transaction
objects to process (execute) later on, maybe by wrapping
this batch function in a custom commit/create_all transaction
method.

queue = TransactionQueue()
queue.add(tx)
...
def create_all(queue):
for tx in queue:
db.execute(tx)

Kind regards,

Etienne
> On Thu, May 7, 2009 at 10:12, Etienne Robillard <robillard.etie...@gmail.com

lekmalek

unread,
May 8, 2009, 9:32:13 AM5/8/09
to sch...@googlegroups.com

hi,

did you have a look at shevo.transaction.Combination, with
bulk_mode=True passed to execute(), it might be what you're looking for.

hope it helps

malek

Matthew Scott

unread,
May 8, 2009, 11:16:22 AM5/8/09
to sch...@googlegroups.com

On Fri, May 8, 2009 at 06:22, erob <robillar...@gmail.com> wrote:
Also, how can we create a batch of new entities ?


As Malek pointed out, we have that covered.  :)

Though the documentation still needs improvement, you can consider Schevo to have been put through its paces as far as its API design.  If you find yourself doing some low-level wrapping or management of Schevo objects, you may find that deeper inspection reveals that a solution already exists.

schevo.transaction.Combination is here:

Example usage:

    from schevo.transaction import Combination
    tx1 = db.Foo.t.create(name='one')
    tx2 = db.Foo.t.create(name='two')
    tx3 = db.Foo.t.create(name='three')
    combined = Combination([tx1, tx2, tx3])
    foo1, foo2, foo3 = db.execute(combined)   # Executes as "all or nothing"


--
Matthew R. Scott

Etienne Robillard

unread,
May 10, 2009, 10:18:55 PM5/10/09
to sch...@googlegroups.com

Hi Malek and Matthew,

Thanks for the replies, I appreciate your input! ;)

> As Malek pointed out, we have that covered. :)
> Though the documentation still needs improvement, you can consider
> Schevo to have been put through its paces as far as its API design.
> If you find yourself doing some low-level wrapping or management of
> Schevo objects, you may find that deeper inspection reveals that a
> solution already exists.
>
> schevo.transaction.Combination is here:
> http://github.com/gldnspud/schevo/blob/feba3e006695c4bf182e7a97e57a035278123fa6/schevo/transaction.py#L552
>
> Example usage:
>
> from schevo.transaction import Combination
> tx1 = db.Foo.t.create(name='one')
> tx2 = db.Foo.t.create(name='two')
> tx3 = db.Foo.t.create(name='three')
> combined = Combination([tx1, tx2, tx3])
> foo1, foo2, foo3 = db.execute(combined) # Executes as "all or
> nothing"

I will look into it. It seems what I'm looking for but would still
like wrapping it in a queue-like interface. :)

Also, I'm having some light problems editing entities using the
SchevoGtk app. I managed to install it, but something seems
broken when trying to edit a field value:

steiner@lisa:~/notmm-schevo/tests/blogengine$ schevo gnav blogengine.db
/home/steiner/ncvs/schevo-git/schevo/field.py:9: DeprecationWarning:
the md5 module is deprecated; use hashlib instead import md5
22:11:26 environ No en_CA translation found for domain kiwi
22:11:26 environ No en_CA translation found for domain
gazpacho Schevo 3.1b1dev-20090505 :: Database Navigator

/usr/local/lib/python2.6/site-packages/gazpacho/loader/loader.py:496:
DeprecationWarning: Use the new widget gtk.Tooltip self._tooltips =
gtk.Tooltips() /usr/local/lib/python2.6/site-packages/gazpacho/loader/loader.py:497:
DeprecationWarning: Use the new widget gtk.Tooltip
self._tooltips.enable() Opened database blogengine.db
Starting Navigator UI...
Traceback (most recent call last):
File "/home/steiner/ncvs/schevo-gtk/schevogtk2/navigator.py", line
59, in on_entity_grid__action_selected self._on_action_selected(widget,
action) File "/home/steiner/ncvs/schevo-gtk/schevogtk2/window.py", line
112, in _on_action_selected tx = action.method()
File "/home/steiner/ncvs/schevo-git/schevo/entity.py", line 547, in
t_update tx = self._Update(self, **kw)
File "/home/steiner/ncvs/schevo-git/schevo/transaction.py", line 491,
in __init__ resolve_valid_values(self)
File "/home/steiner/ncvs/schevo-git/schevo/transaction.py", line 934,
in resolve_valid_values field_names = list(tx.f)
File "/home/steiner/ncvs/schevo-git/schevo/namespace.py", line 87, in
__getattr__ return self._i._field_map[name]
KeyError: '__length_hint__'

Matthew Scott

unread,
May 10, 2009, 11:24:43 PM5/10/09
to sch...@googlegroups.com
This is one of the Python 2.6 things that was holding up the "all green" status of the buildbot until I fixed it.

Use "easy_install -U Schevo==dev" to get the latest development version that has a fix for this.


On Sun, May 10, 2009 at 19:18, Etienne Robillard <robillar...@gmail.com> wrote:
 File "/home/steiner/ncvs/schevo-git/schevo/namespace.py", line 87, in
__getattr__ return self._i._field_map[name]
KeyError: '__length_hint__'



--
Matthew R. Scott

Etienne Robillard

unread,
May 11, 2009, 9:41:12 AM5/11/09
to sch...@googlegroups.com

Yup, it seems that switching to "Schevo==dev" fixes this.
However I still have one unresolved issue trying to update a
field that specifies multiline=True in the schema. The TextView
control seems to be rendered all greyed out and seems to disallow
editing even when I use the set_editable(True) method on the TextView
instance. I'm not very used to pygtk programming so this might be
easier for you to spot.

Kind Regards

Etienne


N.B: In schevogtk2/field.py, I made several attempts to fix this, but
failed. So here's the resulting function, hoping it could still helps
someone.. :)

@optimize.do_not_optimize
def _set_field_multiline_string(container, db, field, change_cb):
if isinstance(field, schevo.field.String) and field.multiline:
value = field.value
container.expand = True

if value is UNASSIGNED:
value = ''
elif isinstance(value, unicode):
value = unicode(value)
else:
value = str(value)

widget = gtk.ScrolledWindow()
widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
widget.set_shadow_type(gtk.SHADOW_ETCHED_IN)
widget.props.sensitive = False

textview = gtk.TextView()
if field.monospace:
textview.modify_font(MONO_FONT)

textview.set_accepts_tab(False)
textview.set_editable(True) # set this to True for editable mode
textview.set_size_request(-1, 150)

textbuff = textview.get_buffer()
textbuff.set_text(value)
textbuff.connect('changed', change_cb, field)

widget.add(textview)
widget.show_all()

return (False, widget, textview)
else:
return (True, None, None)

erob

unread,
May 12, 2009, 8:47:36 AM5/12/09
to Schevo
Let me know if this would be better described
in a support ticket.. :)

Thanks!

Etienne


On May 11, 9:41 am, Etienne Robillard <robillard.etie...@gmail.com>
wrote:

Etienne Robillard

unread,
May 12, 2009, 9:53:22 PM5/12/09
to Matthew Scott, sch...@googlegroups.com

Hi,

I think I managed to fix the last issue I was talking about, on
updating multiline fields using the SchevoGtk2 navigator.

I've cut and pasted a patch below this thread. I'm satisfied by it but
its mostly a very basic fix. Comments welcome!

Kind Regards

Etienne
diff --git a/schevogtk2/field.py b/schevogtk2/field.py
index f88ca76..0267142 100644
--- a/schevogtk2/field.py
+++ b/schevogtk2/field.py
@@ -142,7 +142,7 @@ class DynamicField(gtk.HBox):

def _on_widget__value_changed(self, widget, field):
value = self.get_value()
-## print '%s changed to: %s %r:' % (field.name, value, value)
+# print '%s changed to: %s %r:' % (field.name, value, value)
self.emit('value-changed')

def _on_widget__view_clicked(self, widget, entity_to_view):
@@ -257,7 +257,8 @@ def _get_value_EntityChooser(widget):
@optimize.do_not_optimize
def _get_value_TextView(widget):
if isinstance(widget, gtk.TextView):
- text_buffer = widget.props.buffer
+ text_buffer = widget.get_buffer()
+# text_buffer = widget.props.buffer
startiter, enditer = text_buffer.get_bounds()
value = text_buffer.get_text(startiter, enditer)
if not value:
@@ -362,26 +363,42 @@ def _set_field_image(container, db, field,
change_cb): @optimize.do_not_optimize
def _set_field_multiline_string(container, db, field, change_cb):
if isinstance(field, schevo.field.String) and field.multiline:
+
value = field.value
container.expand = True
+
if value is UNASSIGNED:
value = ''
- else:
+ elif isinstance(value, unicode):
value = unicode(value)
+ else:
+ value = str(value)
+
widget = gtk.ScrolledWindow()
- widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
- widget.set_shadow_type(gtk.SHADOW_ETCHED_IN)
- widget.props.sensitive = False
+ widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+# widget.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+# widget.props.sensitive = False
+
textview = gtk.TextView()
if field.monospace:
textview.modify_font(MONO_FONT)
+
textview.set_accepts_tab(False)
- textview.show()
+ textview.set_editable(True) # set this to True for editable
mode textview.set_size_request(-1, 150)
- textbuff = textview.props.buffer
+
+ textbuff = textview.get_buffer()
textbuff.set_text(value)
-# textbuff.connect('changed', change_cb, field)
+
+ if not field.readonly:
+ try:
+ textbuff.connect('value-changed', change_cb, field)
+ except TypeError:
+ textbuff.connect('changed', change_cb, field)
+
widget.add(textview)
+ widget.show_all()
+

Matthew Scott

unread,
May 12, 2009, 10:51:40 PM5/12/09
to sch...@googlegroups.com
On Tue, May 12, 2009 at 18:53, Etienne Robillard <robillar...@gmail.com> wrote:
I think I managed to fix the last issue I was talking about, on
updating multiline fields using the SchevoGtk2 navigator.

Good to hear!  I don't regularly work with PyGTK code right now, so I'm glad you were able to find a fix.  When I get a chance to review it fully I'll incorporate it into SchevoGtk.


--
Matthew R. Scott

Etienne Robillard

unread,
May 13, 2009, 7:04:50 AM5/13/09
to Matthew Scott, sch...@googlegroups.com

Great. I like SchevoGtk2 look-and-feel so far and intent
to make some other small improvements, as I've started
collecting assorted bugs I'd like to fix.

Moreover, I made a Mercurial repository that follows the current git
branch of SchevoGtk here:

http://joelia.gthc.org/schevo-gtk/

I hope to use it for experimenting myself with Schevo and PyGtk, and
perhaps could be useful for contributing to the main development branch
as well.


Thanks and Regards

Etienne

Matthew Scott

unread,
May 13, 2009, 10:54:07 AM5/13/09
to Etienne Robillard, sch...@googlegroups.com
Glad you like the SchevoGtk2 look-and-feel.  It's been used in production with two or three commercial apps.

One of these days there will be a two-way git<-->hg tool and it won't matter which one we use.  :)

We're close, though:  http://hg-git.github.com/  —  perhaps we can use that somehow to incorporate your changes rather than manually applying patches.


On Wed, May 13, 2009 at 04:04, Etienne Robillard <robillar...@gmail.com> wrote:
Moreover, I made a Mercurial repository that follows the current git
branch of SchevoGtk here:

 http://joelia.gthc.org/schevo-gtk/

I hope to use it for experimenting myself with Schevo and PyGtk, and
perhaps could be useful for contributing to the main development branch
as well.



--
Matthew R. Scott
Reply all
Reply to author
Forward
0 new messages