SebastiΓ‘n RamΓ­rez Profile picture
Dec 4, 2020 β€’ 80 tweets β€’ 29 min read β€’ Read on X
During the next days, I will be sharing here, in small batches, a short summary of my keynote talk at @PyConChina.

Let's explore some "Modern Python through FastAPI and friends" πŸπŸ˜ŽπŸš€ Image
Hey! πŸ‘‹ This is me. I work at @explosion_ai. We build very cool stuff.

And I created FastAPI and Typer (that's why they invited me πŸ˜…).

fastapi.tiangolo.com
typer.tiangolo.com Image
If you don't know, FastAPI is a web API framework, it has been growing, and a bunch of organizations are using it. 😁

And you get quite decent performance (more on that later). πŸš€ Image
I'll share some ideas about modern Python, so, the currently supported versions (3.6 and above).

πŸ“ f-strings (a bit)
πŸ§™ Type annotations (a lot)
⏱ async / await
⚑ Performance
πŸ‘₯ Community

I'll show you FastAPI, Typer, and friends as examples. Image
The first Twitter batch (today) will be about f-strings. πŸ“

This is the shortest/simplest part, we have to start somewhere. 🀷 Image
Let's take this example code. All on the same file.

To format the "message", we have to repeat the text "name" 3 times.

That's a lot of code repetition. πŸ˜‘ Image
We can reduce code repetition using an f-string, just a string with an "f" before the first quote, with variables inside. πŸ€“

We just need to make sure the variables are available right outside the f-string. Image
And if we call it, it just works, as normally.

And we saved a lot of code repetition. πŸŽ‰

...that's it for this first batch. I'll add more here during the next days. πŸ‘‹ Image
Part 2: Let's talk more about Modern Python! πŸπŸ˜ŽπŸš€

This time, about type annotations, also called "type hints" and why they are awesome. πŸ§™ Image
I'll use the same example from the beginning.

We don't want the title "crunchy-frog", we want "Crunchy Frog".

There's a method to change one string for another (e.g. dash for space). What's the method name? "sub"? ❓

Let's trigger autocomplete... oh, no, it doesn't work 😩 Image
But we can just annotate the "name" with a str type πŸ§™ Image
And suddenly we have autocompletion! πŸ’ƒ Image
The editor is smart enough to know that the result is also a str. So it can keep giving us autocompletion. πŸŽ‰ Image
And with that help, we will probably get the code right on the first try more often. 😎

There it is, the delicious "Crunchy Frog". 🐸 Image
Now, as we don't know if everyone really wants one, more, or just the recipe, let's refactor "quantity" to default to None.

Yeah, that's simple, right? 🀷 Image
Oh, no! There's an error on line 23! 😱

It seems we can't multiply 1 * None 🀦

That's fine. It's an easy/common mistake to make. What is not cool is that we don't notice it 🚨 until we run 🚨 the code. Image
But we can add a type annotation of int, we can even keep the default of None. πŸ§™

That change is easy enough. Image
And with just that change, the editor and tools can infer that the variable "quantity" can be an int or None.

And will show us the error right there in the code ✨before we run it ✨. Image
Now that we know what could go wrong, we can simply fix it. πŸ›

Let's create the data first... Image
...and add the total later. Image
What's that error now? The editor and tools see we are using type annotations and try to be even smarter. πŸ€“

So they infer the type of the dict from the existing data, using the last key (string) and value (a list of strings). Image
We can tell the editor and tools "don't try so hard to infer the type, this is a dict of whatever, don't bother about the values". 🀷

We do that by annotating the "result" as a plain dict. Image
Also see that the editor and tools are smart enough to know that quantity could be an int, or also None. πŸ€“ Image
But even better, inside an if statement checking that it is not None, the editor and tools will know that the only possible type (in that block) is int (not None). πŸ§™βœ¨ Image
And we can be even more explicit/formal/strict and annotate the variable as an "Optional" int. That means it can be an int or None. πŸ€“ Image
Here are some of the people that did a lot of the work behind these type annotations and tools, so that we can use them now in Modern Python. 🐍✨

@JukkaLeh
@ILevkivskyi
@msully4321

That's it for today. I'll share more on Modern Python here tomorrow. πŸ‘‹ Image
Part 3: In our exploration of Modern Python, let's make a web API with type annotations, using FastAPI. πŸš€ Image
Let's extend the previous example.

Just import and create a FastAPI app, and decorate the function. ✨

The path "/recipes/{name}" means "name" is a path parameter. Image
Of course, thanks to type annotations, we still have autocompletion. πŸ§™ Image
And again, thanks to type annotations, we still have type error checks. πŸ’― Image
And FastAPI uses the standard type annotations to create an API with interactive documentation for us. πŸ“ Image
It's ✨ interactive ✨, we can send requests live and receive the responses. Image
And we get automatic data validation for those type annotations. πŸ›‘

If we pass something that is not an integer, the UI complains. Image
Of course, even if a client "cheats" and sends a request from the CLI, FastAPI will validate the data and send a nice validation error. πŸ›‘ Image
If we pass valid data, the "2" will still go in the URL, and the URL is naturally really just a long string.

But FastAPI is smart enough to also do data conversion from those type annotations. πŸ§ͺ Image
...so, our code (and here, the response) will see an actual integer where it was declared, instead of the string "2". πŸ§ͺ Image
FastAPI uses the standard type annotations combined with several standards, so we get that nice automatic UI (provided by @SwaggerApi). 🎨

And thanks to the same type annotations, we get autocompletion and type checks. ✨

That's it for today. More Modern Python later! πŸπŸ‘‹ Image
Part 4: More modern Python! πŸπŸš€

Let's use the standard type annotations to create a command line interface (CLI) application with Typer. Image
Again, the same code example...

We just import typer, create an app, and decorate the same function, with the same type annotations. ✨

This time, we don't want to only "return", we also want to print on screen with typer.echo() to see the result. Image
Typer will use that to create a nice CLI, that detects required parameters, and includes an automatic --help option. ⌨ Image
Typer will automatically create CLI Arguments from the type annotations. πŸš€ Image
It will also automatically create CLI Options, like --quantity, when they have default values. Image
Typer will use the standard type annotations to do data validation and data conversion. πŸ§™ Image
When a CLI app created with Typer is installed, the user will have shell completion. ✨

In this example, it's an app also called typer. Image
But what we print is not looking very nice. Let's make it pretty with Rich. 🎨 Image
We just create a Rich table and print with Rich's console. Image
And now we have a very nice terminal output with our data. 😎 Image
Typer is based on Click, it's used for everything underneath.

Typer mainly adds the layer to handle it all from standard type annotations. πŸ§™

Click is maintained by @davidism.

And Rich was created by @willmcgugan.

More about Typer: typer.tiangolo.com Image
Part 5: Let's talk more about modern Python with type annotations. πŸ§™

With FastAPI and Pydantic.

Pydantic is what powers all the data handling underneath in FastAPI, and it's great as a standalone library as well. πŸš€ Image
We can use Pydantic to create a class using standard type annotations, pretty much like with dataclasses. πŸ€– Image
Then use that Pydantic class (model) to declare the body of a request in our API with FastAPI. πŸš€ Image
The automatic API documentation will show the new data shape (schema) defined with the Pydantic class. 🎨 Image
As the automatic API docs are interactive, you can send actual requests. πŸ“¬ Image
...and get the response as expected. Image
What happens if a client sends invalid data inside of the contents of the JSON message? 🚨 Image
FastAPI will use Pydantic to detect it and return a nice and clear error to the client. πŸ›‘ Image
If we want deeply nested data structures, again, we just use standard type annotations. πŸ§™ Image
Because we are using standard type annotations, autocomplete will keep working. Even for these complex and deeply nested data structures. πŸ§™

(Notice this is a double for loop). πŸŒͺ Image
We also get type error checks in the editor, again, thanks to standard type annotations. ✨ Image
Some of the people behind these tools. πŸ‘₯

FastAPI is built on top of @samuel_colvin's Pydantic for the data handling, and @_tomchristie's Starlette for the web parts.

David Montague also helped a lot, so he deserves a special mention. πŸ€“

That's it for today! πŸ‘‹ Image
Part 6: Let's talk about Modern Python with async and await! πŸš€

This is what drives all the performance in terms of concurrency (things executed during the same time range). πŸŒͺ

So, concurrency ends up being the number of users served per second, by the same code and process. πŸ™‹ Image
So what's the deal with concurrency?

Python is a super-fast language... when you compare it to the network. πŸš…

The network is so slow that it becomes the bottleneck, and the specific language is less important. 🐒 Image
The first idea to improve this: let's serve multiple (slow) network clients with the same (fast) server code.

That's a nice idea, at least in theory. πŸ’‘ Image
But in reality, the way standard Python works (without async and await) is like a grocery shop line.

Each client has to finish their process, slowly counting coins, etc. before the next client can start their request. πŸͺ Image
So, in diagrams, it looks like this. Each client has to wait for the previous one to finish everything (including the slow network) before being able to start sending their request. 😩 Image
With async and await, Python has something like an internal waiter. πŸ’

Each client sits at a table, and orders their food, even though the kitchen hasn't finished preparing the food for several previous clients. πŸ‘¨β€πŸ³ Image
The important thing is that with a waiter, the kitchen is preparing food non-stop. πŸš…

Python is using the processor as much as possible, always computing some request, instead of waiting for the slow network. πŸŒͺ Image
In code, using FastAPI, you create the function to handle a request using async def.

And then, inside, you use await to mark the "await"-compatible points that need to be awaited (that are slow). πŸ€“

Here, using the awesome HTTPX. πŸš€ Image
And of course, everything works as normal. The UI docs still work. 🎨 Image
And you can get responses as normal.

But this time, being able to handle some extra thousands of users per second. πŸš… Image
A caveat: the libraries have to be async/await compatible and use async def for any awaitable function. 🚨

And the internal code shouldn't do slow computations without await-compatibility.

Good news: it's optional with FastAPI and HTTPX. So you don't have to use async/await. ✨ Image
Some people behind these tools πŸ‘₯:

@_tomchristie, creator of Starlette and HTTPX

@florimondmanca, co-maintainer of HTTPX

@andrewgodwin, author of ASGI, the spec to use async/await in Python for the web Image
In terms of concurrency, FastAPI has good performance. πŸš…

This graph is from a well-done third-party benchmark by @TFBenchmarks.

Green lines are Go, blue lines are Python.

So, FastAPI gives you pretty decent performance for an interpreted language. πŸš€ Image
Why is FastAPI fast?

It's built on top of Starlette, normally run with Uvicorn, that uses Uvloop, a high-performance drop-in replacement for asyncio (it powers all the async/await stuff).

And Uvloop and Pydantic are both built with Cython. A sort-of compiled Python. πŸš… Image
Some of the people behind these tools πŸ‘₯:

Again @_tomchristie, creator of Uvicorn (and Starlette, HTTPX, etc)

@1st1 creator of Uvloop

Stefan Behnel, the current maintainer of Cython Image
I have been showing you a bunch of people. πŸ‘₯

I want to highlight that all this work, all these tools, are built and done by normal people like you and me.

Mostly done during our free time, just trying to help others. πŸ™Œ Image
For example, I don't speak Chinese.

But the FastAPI community in China has contributed a lot of translations of the FastAPI docs. πŸ‰ Image
Here are some of the people that help a lot with the FastAPI community in China. πŸ‰

For example, @phy25 is one of the top-3 FastAPI Experts. πŸŽ–

And @waynerv77 is currently the top (external) contributor to FastAPI, for translating a lot of the FastAPI docs. πŸŽ– Image
And you can help too! πŸ€“ (and this doesn't apply only to China).

Help FastAPI: fastapi.tiangolo.com/help-fastapi/

Help with FastAPI translations: fastapi.tiangolo.com/contributing/#…

Or go and help with some of the other projects I have been mentioning! πŸ’ͺ Image
Thanks for exploring some Modern Python through FastAPI and friends with me! πŸš€πŸŽ‰

You can check the FastAPI docs at fastapi.tiangolo.com

End. πŸ‘‹ Image

β€’ β€’ β€’

Missing some Tweet in this thread? You can try to force a refresh
γ€€

Keep Current with SebastiΓ‘n RamΓ­rez

SebastiΓ‘n RamΓ­rez Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @tiangolo

Jul 12, 2022
The biggest Typer release in a long time πŸ€―πŸŽ‰

Deep integration with @textualizeio (@willmcgugan) Rich πŸ’°πŸŽ¨

Still optional, but if you install Rich, or:

pip install "typer[all]"

...your app will shine, by default ✨

Go get version 0.6.1 (a quick bug fix on top of 0.6.0) πŸ”– Image
When your code has an error, you will have a pretty traceback by default 😎

But you can configure it in several ways.

typer.tiangolo.com/tutorial/excep… Image
Rich is now the recommended tool to display information 🎨

typer.tiangolo.com/tutorial/print…
Read 9 tweets
Jul 6, 2022
New Typer release! 0.5.0 πŸ”–

This one has pretty output when the Typer app (your code) has errors. ✨

Now @textualizeio's (@willmcgugan) Rich is an optional dependency, used automatically by Typer. πŸŽ‰

Install with:

pip install "typer[all]"

More examples below πŸ‘‡
Take this broken app as an example...

You can't sum a string with an integer. 😱
...up to now, this is the error you would get, there was quite a lot of noise πŸ””
Read 5 tweets
Aug 24, 2021
Big project, first public release! πŸ“’

✨ SQLModel ✨

...the biggest thing I've built since FastAPI & Typer. πŸ€“

SQL DBs based on Python type hints. 😎

Each model is both a Pydantic and @sqlalchemy model. 🀯

Optimized for FastAPI πŸš€

github.com/tiangolo/sqlmo…
Each SQLModel class is ✨ both ✨ a Pydantic model and a SQLAlchemy model. 🀯

(I had never done so much Python black magic πŸ˜…)
SQLModel was designed to provide the best developer experience possible ✨

With autocompletion everywhere, even when creating a new model instance:
Read 11 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(