New: Portable Classes

Anvil’s great strength is that you can do everything in Python – browser-side and server-side, with just a function call from one to the other.

We’ve just launched a new feature that goes one step further: You can now define your own classes that can be passed between Forms, Server Modules and even Uplink code! Check out an example from our announcement post:

It’s easy to get started, but it’s also heavily customisable. You can control how your objects are serialised and sent over the network, and even use our built-in Capability support to create Data-Tables-like APIs that embed permissions in the objects you return. I’m excited to see what some of our more advanced users do with it!

6 Likes

Absolutely fantastic!!!

I’m excited to see what some of our more advanced users do with it!

Hold my beer…

4 Likes

Very exciting Meredydd! And I was delighted to see you chose YouTube videos for the Capabilities example… right up my street :slight_smile:

1 Like

I’m curious how this plays with the lazy search iterators? When you have code like

  return [Video(row['id'], is_admin)
          for row in app_tables.videos.search(owner=user)]

That’s requiring it to iterate through all the rows that match the query, right? So if we have a case where we have enough rows matching that we don’t want to return everything all at once, we’re better off sticking with search iterators?

I love the capabilities, just trying to wrap my mind around when I’d want to use portable objects/capabilities, and when I’d want to stick with search iterators.

Still reading through the new documentation, and trying to grasp the implications. Given that

anvil.server.session can store anything that a server function can return, except for Media objects. This includes Data Table Rows.

does this now mean that an anvil.server.session can store

  1. objects of a Portable Class type?
  2. objects of type `anvil.server.Capability’?

I built a paging search function into my ORM library.

It caches the search iterator from the data tables query on the server side and returns ‘pages’ of portable objects from there as the client requests them.

2 Likes

@jshaffstall, you’re right that the little code sample I provided searches through all rows of a search iterator. However, it’s entirely possible to use Portable Classes to build your own lazy iterator! The simplest way, if you’re OK with sending the Data Tables search iterator to the client, is to send it as a private attribute of a Portable Class.

Here’s an example that wraps a search iterator, and dynamically instantiates objects:

class PotatoSack:
  def __init__(self):
    self._search = app_tables.potatoes.search()

  def __iter__(self):
    return iter((Potato(row['weight'], row['temperature']) for row in self._search))

Or you could build a lazy iterator entirely yourself, implementing __iter__ and __next__ and calling a server function that gives you a “page” of results at a time. (This is what Owen’s library does.)


If you were using capabilities, you’d want the PotatoSack to have a Capability on, say, ['potatoes'] (or a narrower capability permitting access only to a particular subset), and then hand each Potato a narrowed capability on, say, ['potatoes', 'potato_253'].

2 Likes

Unless I’m doing something silly, it seems the Portable Classes fail with dictionaries where the keys are numeric still. I’ve added some detail about this in my original feature request here: Serialising dictionary with numeric keys

That’s right, @AWSOM – adding support for Portable Classes doesn’t change the other restrictions on which data types are portable, which are fully documented here:

https://anvil.works/docs/server#valid-arguments-and-return-values

(What has changed is that, if you want to build an API around numerical keys, you can build it yourself with Portable Classes!)

Righto! :slight_smile:

For all and sundry regarding the “Capability” model
The term “Capability” was hijacked, for a specific formal, technical use, long before our friends at Anvil came along. Anvil uses it in this formal sense, not in the colloquial sense.