Live Chat

We'll need to share your messages (and your email address if you're logged in) with our live chat provider, Drift. Here's their privacy policy.

If you don't want to do this, you can email us instead at contact@anvil.works.

Blog - Page 4

Using SciPy to Work Out How Many T-Shirts I Need for a Conference
8th of August 2018

How many T-Shirts do I take to PyCon?

When you’re marketing to developers, you go where the developers are. We make a platform for building full-stack web apps with nothing but Python, so we go to developer conferences – particularly Python ones.

Like many sponsors, we give out nifty Anvil-branded T-shirts. But there’s a twist: in order to earn a T-shirt, you’ve got to build something with Anvil. So far, it’s gone pretty well - here’s what it looked like at EuroPython last week:

Now we’re home, and preparing for PyCon UK in September, it’s time to order more shirts. The trouble is, developers come in all shapes and sizes, and the first time we ordered we were way off the mark. (Apologies to the huge number of people who wanted a Women’s Small!)

This time, we can be smarter. We’re a bootstrapped company, so we can’t just blow VC cash on unnecessary mountains of shirts – but we do want every Anvil user to go home with a T-shirt.

How can we use this data to work out how many shirts we need?

Option 1: Exact numbers.

“If last conference used 13 Men’s Medium shirts, we should bring exactly 13 to the next conference.”

This is obviously a bad idea. If even one more medium-sized man writes an app with Anvil, we’re going to run out of shirts. And feel pretty stupid about it, too.

Option 2: Double up

OK, fine, so let’s order 200% of what we expect to need. This will cause us to order 4 rather than 2 Women’s XS (probably sensible)…and 54 rather than 27 Men’s Large (not so much!). That 54th Men’s Large shirt is much less likely to be claimed than the 4th Women’s XS shirt is. It’s the law of large numbers: Larger samples average out more reliably.

Wait. I’m sure there’s a more helpful way of thinking about this than waving my hands and saying “law of large numbers”. Can we capture this insight in a statistical model?

Option 3: Be a bit smarter

Let’s imagine that every person who comes to the conference is a dice-roll. Some percentage of the time, they build an Anvil app and claim their T-shirt. What size they want is also a dice-roll: X% of the time they want a women’s Medium; Y% of the time they want a men’s Small; and so on. We can estimate how big X and Y are, because we know how many shirts we gave out at PyCon US and EuroPython, and we know how many attendees were at those conferences.

Next month, we’re sponsoring PyCon UK, with 700 attendees. How many men’s Medium-size shirts will we need? We can simulate it by rolling that die 700 times, and counting how many times it comes up “men’s Medium”.

Of course, each time we do that “roll 700 dice” procedure, we could get a different total count. This total follows a binomial distribution:

Here I’ve plotted two binomial distributions, using Anvil’s plotting tools. On the left, we’re expecting to give away about 2 shirts, but we could easily need twice that number. On the right, we’re expecting 35, but we’re unlikely to need more than 40 – we’re much more certain with larger numbers. This is the insight we had before – but now we’ve got a model, we can quantify it!

We can wrangle binomial distributions easily with SciPy. We’ll use SciPy’s ppf function to get the 95th centile of this distribution: If our model is correct, there’s a 95% probability we won’t need more shirts than this.

Let’s compute that number:

  from scipy.stats import binom
  # From 1500 attendees, we gave away 13 men’s Medium shirts
  p_mens_medium = 13 / 1500
  # For 700 attendees, there’s a 95% chance we will need no
  # more than this many men's Medium shirts:
  n_shirts_p95 = binom.ppf(0.95, 700, p_mens_medium)
  print(n_shirts_p95)
=> 10.0

So we need to take 10 men’s Medium-size shirts to Cardiff!

Building a T-shirt calculator

Now we have some Python code, we can put a web interface on it really quickly with Anvil. I built a T-shirt calculator that can do this calculation for many sizes of shirt at once. You can use it below, or open the source code in Anvil to see how it works:

Open source code

Feel free to use and share this app. And if you’re going to a developer conference soon, perhaps we’ll see you there!

Anvil News - July
24th of July 2018

It was great meeting everyone at EuroPython! Next up: PyCon UK in Cardiff. Join us there, where we’ll be showing everyone how to build full-stack web apps with nothing but Python!

Meanwhile, here’s what’s new this month:

1. Single Sign-On with Microsoft

Does your organisation use Office 365? Now your users can log into your apps with their Microsoft accounts! Microsoft login (or, to give it its official name, Azure Active Directory) is available for all our Business plan customers.

Click here to read more.

2. Building Email-Driven Apps with Anvil

We’ve already made it easy to build web-based apps. Now it’s just as easy to send and receive email from your code, with our new Email Service.

Check out the code samples, or watch our demo video to see me build an email-receiving app in just a couple of minutes.

3. New Documentation Search

We’ve made it easier than ever to search the Anvil documentation. Next time you’re in the Anvil editor, check out the search box in the toolbar. You can search our tutorials, reference documentation, and selected posts from the Community Forum.

(Speaking of the Community Forum, we’d love to hear your feedback. Come join us there!)

4. Other updates

As always, we’re improving Anvil all the time. Here are a few highlights:

  • Validating user input just got a lot easier, with our new form validation library. Check it out!

  • We’ve introduced a new domain for your apps: Now, by default, your apps are available at <something>.anvil.app. (Don’t worry, the old <something>.anvilapp.net links still work!)

  • We had an idea for improving the saving mechanism, so if you’re on a flaky internet connection saving should feel instant.

Happy building!

Meredydd

Building Email-Driven Apps
18th of July 2018

Sending and responding to email in code

Email is the most popular messaging platform on Earth. We use email to arrange events, to exchange files, and to notify each other when something happens.

You should be able to email your applications too. But to receive email, you need to set up a server somewhere, run an SMTP daemon, and somehow connect that to your code.

We’re here to fix that. Today, we’re delighted to show you the easiest way to build email-driven apps. All you need to do is write a Python function. For example, here’s all the code you need to receive emails and store them in a database:

@anvil.email.handle_message
def incoming_email(msg):
  app_tables.incoming_messages.add_row(
    from_addr=msg.envelope.from_address,
    text=msg.text
  )
  msg.reply(text="Thank you for your message.")

Sending is just as simple:

anvil.email.send(
  to="contact@anvil.works",
  subject="New message",
  text="This is awesome",
  html="This is <b>awesome</b>"
)

Despite its simplicity, it’s also fully featured - you can handle attachments, recipients, and even use DKIM to check that a message is genuine before trusting what it says.

Examples

You can scroll down for a cookbook of common examples, or watch as I build a full disposable-email-address service, and publish it on the web, in four minutes:

Example Snippets Watch video

Video example: Disposable Email

App Source Code
Note: We skim past the UI building pretty fast in that video.
If you want to see how it's done, check out our other tutorials for a slower explanation.

Sample Email Code

Here are a few things you might want to do with email. You can follow along from these code snippets, or view them all in the Anvil editor:

Open Example Code


1. Receiving email and saving it in a database

@anvil.email.handle_message
def incoming_email(msg):
  app_tables.incoming_messages.add_row(
    from_addr=msg.envelope.sender,
    text=msg.text
  )

2. Replying to an email you’ve received

@anvil.email.handle_message
def incoming_email(msg):
  msg.reply(text="Thank you for your message.")

3. Sending email

@anvil.server.callable
def send_a_message(txt):
  anvil.email.send(
    to=["someone@gmail.com"],
    cc=["Someone Else <someone.else@gmail.com>"],
    subject="Hello World",
    text="Hi there!"
  )

4. Handling attachments

All attachments are Anvil Media objects. This means you can upload them from web browsers, store them in databases, make them downloadable, and more.

@anvil.server.callable
def send_by_email(file):
  anvil.email.send(
    to="me@example.com",
    subject="New upload",
    attachments=[file]
  )

Incoming attachments are just as straightforward. Here’s how to save all attachments in a database:

@anvil.email.handle_message
def incoming_email(msg):
  for f in msg.attachments:
    app_tables.files.add_row(file=f)

5. Authenticating senders

Email has historically been easy to spoof. Helpfully, many providers now support DKIM, which lets you verify that the email actually came from the domain it says it did.

The dkim property of the message contains details about all that message’s valid DKIM signatures, and a shortcut to check whether it’s signed by the address in msg.envelope.from_address:

@anvil.email.handle_message
def incoming_email(msg):
  if msg.envelope.from_address == 'me@example.com'
      and msg.dkim.valid_from_sender:
    msg.reply(text="You're the real deal!")

There’s a shorthand, if you only want to accept DKIM-authenticated messages (and reject all others):

@anvil.email.handle_message(require_dkim=True)
def incoming_email(msg):
  if msg.envelope.from_address == 'me@example.com':
    msg.reply(text="You're the real deal!")

6. Rejecting (“bouncing”) messages

@anvil.email.handle_message
def incoming_email(msg):
  raise anvil.email.DeliveryFailure("Nope")
Try it yourself

Start writing email-driven apps for free with Anvil:

Try it now


You can also read more about the Email service in the Anvil reference docs.

Anvil News - May
9th of May 2018

It’s been another monster month for us.

It was great meeting everyone at PyCon, and the crowds around our table were awesome! Check out my 5-minute talk from the conference: Making the Web More Pythonic

As always, we’re improving Anvil all the time. Here are a few things you might have missed:

1. Beautiful apps: New Material Design theme

We’ve published a new Material Design theme! We’ve given our components a facelift and added swappable colour schemes, so it’s now even easier to build beautiful apps.

(Don’t worry, the old theme is still there - it’s now called “Classic”.)

2. Simple objects in Data Tables

If you want to store richer data, you can now add “Simple Object” columns to your Data Tables. These can store strings, numbers, lists, or dicts - that’s any JSON object. And you can search inside them with a powerful query system.

Find out more on our blog: https://anvil.works/blog/simple-object-storage

3. Looking after the details

Here are some things we’ve done this month to make Anvil even more pleasing to use:

  • Easier code navigation - you can hold down the Ctrl key and click on a function or variable to jump to its definition.

  • The new FlowPanel lets you lay out components side-to-side. It’s great for grouping buttons, links or labels right next to each other.

  • We’ve made it easier to drag and drop Link components, so it’s clearer whether you’re dropping something next to a Link or inside it. (I love this when I’m building sidebars for navigation!)

  • More options for displaying images in Image components: Shrink to fit, zoom to fill, or display your image at its original size no matter how big your page is.

  • Want your components closer together, or further apart? Now you can control the spacing in a ColumnPanel with the column_spacing property.

  • We’ve made the Toolbox easier to navigate by highlighting the most commonly used components.

  • Fixed-width layouts are easier now too, with the XYPanel. Most of the time, you won’t be needing a fixed-width layout, but when you do, it’s right there.

Happy building!

Meredydd

Making the Web More Pythonic
15th of May, 2018

The Web is not Pythonic. Can we improve that?

The Web is traditionally a pain to program. It's also seriously un-Pythonic.

At PyCon 2018, I asked: Can we make Web programming easier, by making it more Python-shaped?

Scroll down for transcript
Anvil logo
For more information about Anvil, check out anvil.works.
Transcript:

The Web, I assert, is seriously un-Pythonic. It's also famously a pain to program for. Are these two things related? Could we make the Web a nicer place to program, by making it more Pythonic?

Well, to start with, what do I mean by "the web is un-Pythonic"?

Think about a typical web app. You're going to have to turn your data into a bunch of different shapes along the way:

  1. Your data exists as rows in a database, accessed via SQL.
  2. You then transform it into model objects on the server, with methods and attributes to interact with them.
  3. Now, you have to represent these objects as JSON, and provide a whole bunch of REST endpoints for getting or manipulating them.
  4. On the client, you then transform these HTTP requests into Javascript objects, which have methods of their own.
  5. And then you have to transform these client objects into HTML DOM...
  6. ...and style that to produce pixels on a screen.

Oof.

At each of these boundaries, a bunch of boring and repetitive translation work happens. And that is an invitation to exactly the wrong sort of magic.

Let's take an entirely unfair pot-shot at SQLAlchemy, which is a library that manages the transformation of an SQL database into Python objects (and back). It's actually really good at it. You can even write neat query expressions like this: filter(Book.value<20).

Of course, the process of turning that Python expression into SQL is black magic. It involves metaclasses, and overloading standard Python operators to do something completely different to what they normally do.

And that's cool, if you do it once. But if you have this amount of magic at every boundary in this stack, you're setting yourself up for a bad time.

But of course, that's exactly what we do:

  • We have ORMs to translate databases into objects;
  • We have REST frameworks to help us represent objects as JSON;
  • We have JS frameworks (like Angular's resources) to help us turn patterns of HTTP requests into Javascript objects;
  • We have templating engines to represent JS objects as HTML DOM;
  • And we have CSS frameworks to help us display this DOM as the right pixels.

And they're all extremely leaky abstractions! To be a reasonably advanced user of any of these frameworks, you need to understand everything they do, on both sides of the transformation.

Aside: This is a leading cause of the "Framework of the Week" anti-pattern. You have a tool which is inherently unsatisfactory, because it's spanning one or more of these transitions and suffers from all these impedance mismatches. And just in order to use this tool, you need to know more or less everything you need to build one yourself. This presents an irresistible temptation. But of course the new one still isn't quite right...and around and around we go.

So, how does this situation stack up against The Zen of Python?

"There should be one obvious way to do it"?

Hoo, boy. Look at all these frameworks!

"Explicit is better than implicit"?

Transforming data implicitly is these frameworks' job.

"If you can't explain the implementation, it's a bad idea"?

Again, look at the sheer amount of magic in every level of this stack!

So, what might something more Pythonic look like?

At Anvil, we start by putting Python everywhere — even in the browser. (We use the Skulpt Python-to-Javascript compiler; check out my previous talk about it.)

OK, so if we're in Python, and making an HTTP request to a Python server, what happens?

Well, we make a function call into the requests library, and then some time later it emerges as a function call to a Flask endpoint.

Wait a second. If a function call was all we wanted, why not explicitly turn the whole thing into function calls?

So that's what we do. Have a function on the server, decorate it with @anvil.server.callable, and call it from the client with a function call.

Now we can pass arguments (even keyword arguments), and return values from the function. We don't have to marshal everything into an HTTP request any more — it's just a Python function call.

(The data still passes over HTTP, of course. Actually, we use an encrypted WebSocket.)

OK, so the next question is, "What sorts of data should you be able to pass into, or return out of, these functions?"

Well, strings, numbers, dicts, and lists are easy. That's just JSON. But we want to avoid translations, so we want to pass proper objects from the server to the client.

Unfortunately, this is a web server, serving lots of clients, so it has to be stateless: the server just can't afford to keep these objects in RAM.

So we support passing a special sort of object: a stateless server object.

What's in a stateless object? Well, it has an immutable ID, some method names, and some permissions. That's all. (So there's nothing else the server has to remember.)

We can call methods on this object from the client: it's just a server function call, like we saw on the last slide. We make sure the client can't call methods on arbitrary objects by signing the ID and permissions, and requiring that signature to call a method on an object. So the client can only call methods on an object that has been returned from a server function.

An excellent use case for this is...database rows! The object's ID is the unique ID of that row in the database; the methods are things like update() and delete(). And by implementing __getitem__() and __setitem__(), we can even use square-bracket lookup to get and set column values.

If we put this together, we can:

  • Make a simple function call to the server,
  • Look up a database row,
  • Return that row to the client as a Python object,
  • ...and use the values from that row in client code.

We've skipped a whole bunch of these translation steps! We've got one object, passed all the way from the database to client code.

And that's a little contribution to making the Web more Pythonic.

For more about Anvil, check out https://anvil.works.

Thank you very much.




Learn More

Get the best out of Anvil with our free email course.