After nine months of development and extensive testing, the new Camelot release is available for download.  Highlights in this release are :

Picture
Camelot now uses SQLAlchemy 0.8.0
All built in models have been moved from Elixir to Declarative.  Camelot now includes replacement classes that mimic the Elixir definitions and integrate with Declarative.  Migrating from Elixir to Declarative is now effortless, more information is available in the migration guide.

Picture
Improved import and export actions.  Data in arbitrary columns can be imported from csv, xls and xlsx files.  This machinery can be reused to develop custom importers.

Picture
The history of every form can be reviewed from within the form itself.

Picture
The print preview screen has an edit button, this allows users to make last minute changes to reports and generated documents without developer intervention or the need to modify templates.

Picture
Search splits search strings between spaces and searches for a combinations of the elements in the different columns of the table.

Other enhancements include :
  • Updated translations, thanks to the community.
  • Support for database reflection through SQLAlchemy.
  • The unittests now cover 80% of the code
 
 
One of the most asked questions on the mailing list is about how to customize this or that part of the GUI.  There isn't really a standard answer for this, hence this blog post with a concrete example.

Camelot comes with lots of predefined GUI elements which are easily bound to your data model.  This has the advantage of getting your project up and running in no time.  But once you want to start customizing the GUI beyond what Camelot provides out-of-the-box, you need to switch gears.

Suddenly, you need to know all about SQLAlchemy, Qt, PyQt/PySide and the internals of Camelot.  There is no way around this, but this post aims to be a gentle introduction.

In this post, we'll change the movie store example, to show a chart in the table view when a row is clicked, instead of opening a form.

Actions

The first thing you need to know is that most customizations of the GUI can be done through the Actions framework.  The Actions framework is some kind of mini-framework inside Camelot.  Every time the user clicks a button in a Camelot application to do something, an Action is triggered, and those Actions can be customized.

Make sure to read the Actions Tutorial to get a good idea of how actions work and how to write them.

In this case, when the user clicks on a row in the table, we want a chart to show up beneath the list, instead of a form that opens.  We'll intercept the default action that opens the form and put our own action in place :

Threads

Programming with multiple threads sounds scary. However multiple threads or processes are essential to keep an application responsive to a user.  Camelot runs two threads, one for accessing the GUI, and one for accessing the data model.  So as a developer, you should always keep those two things clearly separated.  Doing so will ensure that your application remains responsive.  Whenever you write an action, you should ask yourself if the action starts with doing something in the model, or does it start with doing something in the GUI.
Actions that start in the model should overwrite the model_run method.  In this case, the first thing we want to do is to strip all the data for the chart from the model.
We'll assume for a moment you are aware how the Matplotlib integration in Camelot works.  The model_run method receives the model_context argument.  The model context provides access to those parts of the model that are active when the action was triggered.  We use the model context to get to the movie object that
was selected, and then create the chart.  Once the chart is made, we yield an ActionStep, in this case UpdateChart to display the chart in the GUI.  Yielding the action step will pass control to the GUI.

GUI

Of course the UpdateChart action step does not exist yet, so we'll have to create that one as well :
In the gui_run method, we receive the gui_context object.  The gui context provides access to the the relevant widgets we need.  One of the fine things of Qt is that every widget can have a name and you can find a widget with a certain name inside a widget tree with the findChild method.  This can be handy to look for Camelot widgets (most widgets in Camelot have a name, to find out which one, look at the source code) or your own widgets, and manipulate them accordingly.

Both Qt and Camelot have a set of editors, here we'll reuse the ChartEditor from Camelot to display the chart.  So we create a chart_editor, and add it to the layout of the table view.

Conclusion

Wow, glad you made it.  I hope this article can convince you that investing some time in PyQt/PySide can help a lot when you need to customize Camelot beyond what it provides out of the box.  The users of your application will certainly appreciate it.  For questions, please consider the mailing list.
In October and November, we're organizing a set of SQLAlchemy, Camelot and Python courses that provide you with the necessary skills and backround information to enjoy developing these kind of applications.
 
 
Picture
Release 12.06.29 is out.  The biggest change in this release is the switch from Elixir to Declarative.  All documentation and sample code has been adapted to reflect this change.  Elixir is still supported, so all your code will stay working.  Please have a look at the upgrade notes before upgrading your application.

Other changes are :
  •  A toolbar in the form view, with an exit button
  • A new progress widget
  • Column groups in the table view
  • Cleanup of the built-in models
  • Store the column width if the user changes it
  • Lots of bugfixes

 
 
An ongoing challenge when building business applications is to give the user a lot of information while presenting everything in a clear way.

Camelot makes it possible to create a tabbed table view.  In such a table view there are a large number of columns,  but only a selected number of columns are shown together.  The user can switch from on group of columns to another group of columns by selecting a tab in the table view.

Switching from one group of columns to another preserves the current selection of rows and the place in the table.
The code for the Admin of this table would look like this :

    from camelot.admin.table import ColumnGroup 
class Admin( EntityAdmin ):
list_display = [ ColumnGroup( _('Planning'), planning_parameters ),
ColumnGroup( _('Scharnieren'), scharnier_parameters ),
ColumnGroup( _('Glasopening'), glasopening_parameters ),
ColumnGroup( _('Roosters'), rooster_parameters ),
ColumnGroup( _('Beslag'), beslag_parameters ),
ColumnGroup( _('Opties'), optie_parameters ),
ColumnGroup( _('Details'), detail_parameters ),
]
This feature will be available in the upcoming release.
 
 
For some time now, SQLAlchemy has an excellent extension for defining models, called Declarative.  Declarative can be used as an alternative to Elixir to define the model in a Camelot application.

The only thing you need to do is to define a declarative base class that will add newly created objects to the global Elixir session when a new object is constructed.

Then every class in the model definition should inherit from this base class.  This is demonstrated in the code below, for convenience, the declarative base class is named Entity.

Future versions of Camelot will include such a base class.  This code is prepared in the no-elixir branch of Camelot.

import sqlalchemy.types 
from sqlalchemy import Column
from sqlalchemy.ext.declarative import ( declarative_base,
_declarative_constructor )

from camelot.admin.entity_admin import EntityAdmin
from camelot.model import metadata
import camelot.types

from elixir import session

class Entity( object ):

def __init__( self, **kwargs ):
_declarative_constructor( self, **kwargs )
session.add( self )

Entity = declarative_base( cls = Entity,
metadata = metadata,
constructor = None )

class Movie( Entity ):

__tablename__ = 'movie'

id = Column( sqlalchemy.types.Integer, primary_key = True )
name = Column( sqlalchemy.types.Unicode(50), nullable = False )
cover = Column( camelot.types.Image(), nullable = True )

class Admin( EntityAdmin ):
list_display = ['name']
form_display = ['name', 'cover']




 
 
The default Camelot model went through a series of changes :
  • The relational model behind the objects has been simplified
  • It is now easy to use various parts of the default model independent of each other
  • Camelot can work without any of the default models
To adapt your database and application to the new default model,
have a look here.
 
 
There is a Github mirror to the Gitorious master repo.
We'll see if it is useful for social stuff and contribution.

Bear in mind that the mirroring is done through a private server and
is not guaranteed. That said, if both repos are not in sync, feel free
to bring it to my attention, preferably on the mailing list.

Github mirror is here: https://github.com/jeroendierckx/Camelot
Gitorious master repo is here: https://gitorious.org/camelot

Sync is done the second minute of every hour.
 
 
Camelot 11.12.29 was uploaded to pypi, run easy_install camelot to update.  The focus of this release was moving to SQLAlchemy 7.x and making the GUI more customizable.  It is now straightforward to change the menu and the toolbar.  As a bonus the code base was reduced with 4%.

  • Import from file wizard supports importing excel files
  • A number of new ActionStep classes
  • Move the repository to gitorious
  • The toolbar in the one-to-many and many-to-many editor are configurable using the ObjectAdmin.get_related_toolbar_actions() method.
  • Spanish translations
  • Possibility to add a close button to a form and to customize the form close action
  • Filters can have a default value
  • Main menu and toolbars are configurable in the ApplicationAdmin through the use of actions, which allows creation of reduced main windows
  • Rewrite of Camelot functions behind toolbars and menus to actions, resulting in a number of Action classes with sample code
  • Move to SQLAlchemy 7.x
  • Undefer all fields that are going to be used in a view when querying the database
 
 
Using a reduced main window and the PySide bindings.
 
 
With the new actions in place, it's now very easy to add a Close Button to a form :
from camelot.admin.action.form_action import CloseForm
form_actions = [CloseForm(), BurnToDisk()]