spyce
         
home     documentation     download     Spyce logo


What's new in 2.1

New features in Spyce 2.1 include
  • Login tags
  • SQLAlchemy integration
  • Validation in handlers
  • More powerful form tags
  • Improved handler integration
Let's have a look at these in the context of an example. (You can log in as spyce / spyce.)

examples/whatsnew.spy
<spy:parent title="What's new in Spyce 2.1" />

<spy:login_required />

[[!
def list_new(self, api, name):
    if api.db.todo_lists.selectfirst_by(name=name):
        raise HandlerError('New list', 'a list with that description already exists')
    api.db.todo_lists.insert(name=name)
    api.db.flush()
]]

<h2>To-do lists</h2>

[[ lists = db.todo_lists.select(order_by=db.todo_lists.c.name) ]]
<spy:ul data="[L.name for L in lists]" />

<h2>New list</h2>
<f:form>
<f:submit value="New list" handler=self.list_new />:
<f:text name=name value="" />
</f:form>
Run this code

Login tags

Login tags allow you to easily require authentication for your pages:

<spy:login_required />
That's it!

Login policy (what to allow as valid logins) is configured with a simple function in your Spyce config file. The Spyce login framework will pass the login and password to your function, and your function returns either a login ID, or None for a failed login. Here's what a simple database-backed validator might look:

def validator(login, password):
    user = db.users.selectone_by(name=login, password=password)
    if user:
        return user.id
    return None

You can override the default authentication funtion on a per-page basis; you can also eaily customize the look of the generated login. Logout and (non-required) login tags are also provided.

Login tags are covered in detail in the core tag library docs.

SQLAlchemy integration

Besides request and response, Spyce now automatically adds a hook to db in each script's namespace (meaning these references are available without any explicit imports). db is instance of sqlalchemy.ext.SqlSoup, which allows you to easily access your data without SQL or even pre-defined Python classes:

[[ lists = db.todo_lists.select(order_by=db.todo_lists.c.name) ]]
Or with the api prefix in a handler,
api.db.todo_lists.selectfirst_by(name=name)

Jonathan Ellis blogged about an early version SqlSoup a few months ago; the biggest change since in the final version is Join support. Spyce 2.1 includes up-to-date docs.

Validation in handlers

raise HandlerError('New list', 'a list with that description already exists')
That's all it takes! Try to create a duplicate list to see how Spyce renders this in a user-friendly way.

To display multiple errors at once, use a CompoundHandlerError. See the Active Handlers docs for details.

Time for one more example

The last two sections will reference the following example. This code is very similar to the last example, but it illustrates a couple more features:

examples/whatsnew2.spy
<spy:parent title="What's new in Spyce 2.1 (part 2)" />

[[!
def list_select(self, api, items):
    self.selected = ', '.join(items)
]]

[[ lists = db.todo_lists.select(order_by=db.todo_lists.c.name) ]]

<h2>Select lists</h2>
<f:form>
<f:select name="items:list" multiple="True" data="[(L.name, L.name) for L in lists]" />
<f:submit value="Go" handler=self.list_select />
</f:form>

[[ if hasattr(self, 'selected'):{ ]]
  Selected: [[= self.selected ]]
[[ } ]]
Run this code

More powerful form tags

Spyce 2.1 includes compound form controls, similar to the list control used in the first example (spy:ul). f:select is one:

<f:select name="items:list" multiple="True" data="[(L.name, L.name) for L in lists]" />
The other compound form controls are checkboxlist and radiolist. See the docs on the form tag library for details. (And the core tag library for details on the list and table controls.)

There's also an example of all the form tags.

Improved handler integration

Spyce 2.1 allows you to define data types for your form elements by appending :int, :list, :float, or :bool to their name. When you do, Spyce will perform the appropriate casts before passing the data to the handler method, so you don't have to write boilerplate like "items = list(int(i) for i in items)" in your handlers anymore. So in the same line we looked at earlier,
<f:select name="items:list" multiple="True" data="[(L.name, L.name) for L in lists]" />

since we specify :list in the select's name, Spyce collects all the selected values into the "items" handler parameter.

That's it!

Welcome to Spyce 2.1! Please don't hesitate to drop us a line on the mailing list if you have any questions!


Spyce logo
Python Server Pages
version 2.1.3
Spyce Powered SourceForge Logo