<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eli Holderness</title>
    <description>The latest articles on DEV Community by Eli Holderness (@eliholderness).</description>
    <link>https://dev.to/eliholderness</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F500215%2Ff2458be9-3f6a-4d7a-8b43-b62c6260cbe1.jpeg</url>
      <title>DEV Community: Eli Holderness</title>
      <link>https://dev.to/eliholderness</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eliholderness"/>
    <language>en</language>
    <item>
      <title>Using Coiled with Anvil</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Tue, 21 Feb 2023 14:52:25 +0000</pubDate>
      <link>https://dev.to/anvil/using-coiled-with-anvil-300a</link>
      <guid>https://dev.to/anvil/using-coiled-with-anvil-300a</guid>
      <description>&lt;p&gt;If you've got some &lt;em&gt;big&lt;/em&gt; datasets and you want to wrangle some insights from them, you might want to distribute all that heavy-duty computation. &lt;a href="https://coiled.io/" rel="noopener noreferrer"&gt;Coiled&lt;/a&gt; lets you do just that, &lt;em&gt;and&lt;/em&gt; takes the hosting off your plate too. So, of course, I built an app to showcase just how easy it is to use Coiled with Anvil. Today's blog post is a tour of that app and how it works, and it aims to give readers a good idea of how they might extend the app to meet their own needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Ffinished-app-startup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Ffinished-app-startup.png" alt="A screenshot of the finished app."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's what the finished app looks like when it's first loaded. Later, it'll display output data.&lt;/p&gt;

&lt;p&gt;This example app uses Coiled to do some computation on a randomly generated &lt;a href="https://docs.dask.org/en/stable/api.html#datasets" rel="noopener noreferrer"&gt;Dask timeseries dataset&lt;/a&gt;, then generates &lt;a href="https://plotly.com/python/" rel="noopener noreferrer"&gt;Plotly plots&lt;/a&gt; from that output data to display to the user. &lt;/p&gt;

&lt;p&gt;It also shows how to use &lt;a href="https://anvil.works/beta-docs/media/creating_pdfs" rel="noopener noreferrer"&gt;Anvil's PDF generation&lt;/a&gt; to provide a PDF version of that output, for the user to download.&lt;/p&gt;

&lt;p&gt;By the end, you'll know how to use Coiled with Anvil, and be able to build an app of your own!&lt;/p&gt;

&lt;p&gt;Read on to learn more about the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#what-is-coiled" rel="noopener noreferrer"&gt;Coiled, Anvil, and using the two together&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#configuring-your-anvil-apps-server-environment" rel="noopener noreferrer"&gt;Configuring your Anvil server environment for Coiled&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#using-background-tasks" rel="noopener noreferrer"&gt;Using Background Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#wrangling-some-data" rel="noopener noreferrer"&gt;Wrangling some data!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#building-a-ui" rel="noopener noreferrer"&gt;Building a UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#plotting-our-data" rel="noopener noreferrer"&gt;Plotting our output data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/blog/using-coiled-with-anvil#generating-pdf-output" rel="noopener noreferrer"&gt;Generating PDF output&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also &lt;a href="https://anvil.works/build#clone:BRYOCOH7HDXDRGRZ=XSGJX2DUWANUJ3K2TWASQL5Z" rel="noopener noreferrer"&gt;clone the app&lt;/a&gt; to read the code and follow along.&lt;/p&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Coiled?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Fcoiled-logo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Fcoiled-logo.png" alt="The Coiled logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://coiled.io/" rel="noopener noreferrer"&gt;Coiled&lt;/a&gt;  provides a platform for users to spin up clusters for for distributed computation using the popular Python framework, Dask.&lt;/p&gt;

&lt;p&gt;All you have to do is to use it is create an account and link that up an existing &lt;a href="https://docs.coiled.io/user_guide/backends.html" rel="noopener noreferrer"&gt;AWS or GCP account&lt;/a&gt; (so that Coiled knows where to create your clusters!). From there, it's all Python.&lt;/p&gt;

&lt;p&gt;For the purposes of this blog post, I'll be assuming a basic familiarity with Coiled, but all you really need to know is that Coiled is a fast and easy way to do some serious computation - without needing access to any powerful computers yourself. You can see some great examples of Coiled usage on their &lt;a href="https://coiled.io/blog/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Anvil?
&lt;/h2&gt;

&lt;p&gt;Anvil is a platform for building web applications using nothing but Python, which means we need to know a little about the web. In particular, web apps have front-end code, also called client code, (which runs in the user's browser) and back-end code (which runs on a server somewhere). Anvil lets you write both &lt;a href="https://anvil.works/docs/client/python" rel="noopener noreferrer"&gt;front-end&lt;/a&gt; and &lt;a href="https://anvil.works/docs/server" rel="noopener noreferrer"&gt;back-end&lt;/a&gt; code in Python, and communicate by &lt;a href="https://anvil.works/docs/server#calling-server-functions-from-client-code" rel="noopener noreferrer"&gt;calling back-end functions from front-end code&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Anvil also has a &lt;a href="https://anvil.works/beta-docs/editor" rel="noopener noreferrer"&gt;drag-and-drop Editor&lt;/a&gt; for building user interfaces, which we'll be using later in this walkthrough.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://anvil.works/articles/client-vs-server" rel="noopener noreferrer"&gt;Learn more about front ends, back ends, and how web applications work in Anvil!&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How can we use the two together?
&lt;/h2&gt;

&lt;p&gt;You can &lt;a href="https://anvil.works/beta-docs/server/custom-packages" rel="noopener noreferrer"&gt;install any custom package you like&lt;/a&gt; into your Anvil apps' server environments, so we'll be driving Coiled from back end code.&lt;/p&gt;

&lt;p&gt;Coiled is typically used in notebooks such as Jupyter notebooks, or Google Colab notebooks. Anvil's server environments differ slightly from these environments in a couple of ways that are important here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When client code in an Anvil app makes a call to the server, the server environment is created anew each time (unless you're using the &lt;a href="https://anvil.works/docs/server#persistent-server-modules" rel="noopener noreferrer"&gt;Persistent Server&lt;/a&gt; for your Anvil app)&lt;/li&gt;
&lt;li&gt;Normal server calls on Anvil apps have a &lt;a href="https://anvil.works/docs/server#server-function-timeout" rel="noopener noreferrer"&gt;time-out of 30 seconds&lt;/a&gt;, meaning that long-running tasks (such as running a Coiled computation) need to be run as Anvil &lt;a href="https://anvil.works/beta-docs/background-tasks" rel="noopener noreferrer"&gt;Background Tasks&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first point means that we need to make sure that all the &lt;a href="https://docs.coiled.io/user_guide/configuration.html" rel="noopener noreferrer"&gt;necessary configuration&lt;/a&gt; to connect to Coiled is in place every time the server environment loads.&lt;/p&gt;

&lt;p&gt;The second point means that for any long-running function calls, we'll be using Anvil's &lt;a href="https://anvil.works/beta-docs/background-tasks" rel="noopener noreferrer"&gt;Background Tasks&lt;/a&gt;, which are specifically designed to handle situations where a call will take a while to complete.&lt;/p&gt;

&lt;p&gt;With these two things in mind, we're ready to get building. Since Coiled is a Python package, we can &lt;a href="https://anvil.works/learn/tutorials/using-custom-packages" rel="noopener noreferrer"&gt;install it into any Anvil app&lt;/a&gt; with access to custom packages, and we're off!&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring your Anvil app's server environment
&lt;/h2&gt;

&lt;p&gt;Whenever our server environment loads, we'll need it to be correctly configured so that it can connect to Coiled. To do this, we can set the details we need from code using &lt;code&gt;dask.config.set&lt;/code&gt;, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;dask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coiled.user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-coiled-username&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coiled.server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://cloud.coiled.io&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;Adding a &lt;code&gt;dask.config.set&lt;/code&gt; call at the top of our Server Module will ensure that any code that runs in our server environment will be doing so with this configuration in place.&lt;/p&gt;

&lt;p&gt;For this example app, we'll be configuring the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The name of the Coiled account it should connect to&lt;/li&gt;
&lt;li&gt;The name of the specific user within that Coiled account&lt;/li&gt;
&lt;li&gt;An API token associated with this user&lt;/li&gt;
&lt;li&gt;The server that should be used to provision clusters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More information on how to find each of these pieces information can be found &lt;a href="https://docs.coiled.io/user_guide/configuration.html" rel="noopener noreferrer"&gt;in the Coiled documentation&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're used to a notebook environment, you might be familiar with using a &lt;code&gt;config.yaml&lt;/code&gt; file to configure your Coiled environment. You could use the approach detailed in this blog post to set any of the options you'd typically set in a YAML configuration file. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The account name, username and server aren't secret, but the API token should be stored securely. To do this, we'll use Anvil's &lt;a href="https://anvil.works/docs/security/encrypting-secret-data" rel="noopener noreferrer"&gt;App Secrets&lt;/a&gt; so that the token is encrypted at rest, and leave the other configuration details hard-coded.&lt;/p&gt;

&lt;p&gt;That means that we can write a function to configure our Python environment to use Coiled correctly, and that code looks this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dask&lt;/span&gt;
&lt;span class="n"&gt;dask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coiled.token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_secret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;coiled_token&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# get the API token
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coiled.user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eli-holderness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# that's me!
&lt;/span&gt;  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coiled.account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eli-holderness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coiled.server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://cloud.coiled.io&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting this code at the top of our Server Module means that it'll always run before anything else, which is exactly the behaviour we want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Background Tasks
&lt;/h2&gt;

&lt;p&gt;When we actually use Coiled, we'll be doing it from inside a &lt;a href="https://anvil.works/docs/background-tasks" rel="noopener noreferrer"&gt;Background Task&lt;/a&gt;, so that our code has the time it needs to run. These tasks are written in our app's server code, and we'll define two Background Task functions there - one for spinning up a new cluster, and one for doing all the computation.&lt;/p&gt;

&lt;p&gt;For example, here's the code for spinning up a new cluster from a Background Task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DEFAULT_CLUSTER_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anvil-coiled-demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="nd"&gt;@anvil.server.background_task&lt;/span&gt; 
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setup_cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="nf"&gt;setup_config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coiled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;DEFAULT_CLUSTER_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;n_workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;scheduler_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;idle_timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1 hour&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;shutdown_on_close&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that it takes a &lt;code&gt;name&lt;/code&gt; variable as input. When we build our UI, we'll provide a way for the app's user to choose a name for the new cluster, with a default option hard-coded within the Server Module.&lt;/p&gt;

&lt;p&gt;The way to launch a Background Task is from another server function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@anvil.server.callable&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_cluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch_background_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;setup_cluster&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that when the Background Task is launched, a &lt;code&gt;task&lt;/code&gt; variable is returned, which provides the mechanism for callbacks to the task. From within that task's function, we can write to the task's &lt;code&gt;state&lt;/code&gt; (a &lt;code&gt;dict&lt;/code&gt;-like object) with &lt;code&gt;anvil.server.task_state['key'] = value&lt;/code&gt;, and from outside the function we can read that state by calling &lt;code&gt;task.get_state()&lt;/code&gt;. For more detail, see &lt;a href="https://anvil.works/docs/background-tasks/communicating-back" rel="noopener noreferrer"&gt;Communicating with Background Tasks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Later, we'll be using &lt;code&gt;task.get_state()&lt;/code&gt; to retrieve the results of our computation, and &lt;code&gt;task.is_completed()&lt;/code&gt; (which returns &lt;code&gt;True&lt;/code&gt; if the function has finished, and &lt;code&gt;False&lt;/code&gt; otherwise) to check on the status of our long-running tasks from client code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a UI
&lt;/h2&gt;

&lt;p&gt;Next, we're going to build the UI for our app, all in Python, with Anvil's &lt;a href="https://anvil.works/beta-docs/editor" rel="noopener noreferrer"&gt;visual UI editor&lt;/a&gt;. With the Editor, you can &lt;a href="https://anvil.works/beta-docs/client/quickstart" rel="noopener noreferrer"&gt;drag and drop visual components&lt;/a&gt; onto your app, and then interact with these components using &lt;a href="https://anvil.works/beta-docs/client/python" rel="noopener noreferrer"&gt;client-side Python&lt;/a&gt; code. The pages for your app are called Forms, and the app we're going to build will have two Forms - a &lt;code&gt;StartupForm&lt;/code&gt; and a &lt;code&gt;ResultsForm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The app we're building today is actually very simple. It spins up a cluster, connects to that cluster to do some basic computation, then displays the outputs.&lt;/p&gt;

&lt;p&gt;So, we're going to build the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one Form (the &lt;code&gt;StartupForm&lt;/code&gt;) that lets the user choose a name for their new cluster and spin it up, then run the computation&lt;/li&gt;
&lt;li&gt;one Form (the &lt;code&gt;ResultsForm&lt;/code&gt;) that displays the results of that computation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;StartupForm&lt;/code&gt; has a few components: A &lt;a href="https://anvil.works/beta-docs/client/components/basic#textbox" rel="noopener noreferrer"&gt;&lt;code&gt;TextBox&lt;/code&gt;&lt;/a&gt; that asks for a name for the new cluster, two &lt;a href="https://anvil.works/beta-docs/client/components/basic#button" rel="noopener noreferrer"&gt;&lt;code&gt;Button&lt;/code&gt;&lt;/a&gt;s, and some &lt;a href="https://anvil.works/beta-docs/client/components/basic#label" rel="noopener noreferrer"&gt;&lt;code&gt;Label&lt;/code&gt;&lt;/a&gt; elements that display text, including the title of the app.&lt;/p&gt;

&lt;p&gt;Here's how the &lt;code&gt;StartupForm&lt;/code&gt; for our app looks in the Anvil Editor:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Fstartup-form.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Fstartup-form.png" alt="A screenshot of the StartupForm."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not every element will be visible at once; in fact, when the Form is loaded, its initialisation sets some of the UI elements to be either disabled or invisible.&lt;/p&gt;

&lt;p&gt;At the very bottom, there's a &lt;a href="https://anvil.works/beta-docs/client/components/basic#timer" rel="noopener noreferrer"&gt;Timer&lt;/a&gt; element. This is an invisible UI element that can regularly and repeatedly execute code, which makes it perfect for checking on the state of any Background Tasks we launch.&lt;/p&gt;

&lt;p&gt;Here's the initialisation code for the Form, in its &lt;code&gt;__init__&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Set Form properties and Data Bindings.
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init_components&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Any code you write here will run when the form opens.
&lt;/span&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_calculations_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spinning_up_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task_running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_task_running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the Form is loaded, the button to run calculations is disabled, and the text that tells us our cluster is being provisioned is hidden. Later, we'll use code to make that text visible and to enable that button at the appropriate points during the user flow. The Timer element also has its &lt;code&gt;interval&lt;/code&gt; property set to zero, which disables it.&lt;/p&gt;

&lt;p&gt;To start with, the user optionally enters a name into the &lt;code&gt;cluster_name_box&lt;/code&gt; (the text box at the top of the Form), and then clicks the button that says 'Spin up a new cluster'. We need this button to make a call to a server function that will spin up a cluster for us, with the appropriate name.&lt;/p&gt;

&lt;p&gt;Here's the Python function that will run in the browser when that button is clicked. It calls a server function, and changes some visual attributes of the UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;spin_up_button_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is called when the button is clicked&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster_name_box&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_loading_indicator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;start_cluster&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task_running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spin_up_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;spinning_up_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the Form stores the text contents of the &lt;code&gt;cluster_name_box&lt;/code&gt; as an attribute on itself (with &lt;code&gt;self.cluster_name = ...&lt;/code&gt;), and then also passes that name on to the function that will launch our first Background Task.&lt;/p&gt;

&lt;p&gt;Next, there's some state on the client side that needs to be updated; we know that the setup task is now running, so we can disable the button that launches it (that's the button the user just clicked). We can also show the &lt;code&gt;spinning_up_text&lt;/code&gt; label, so that the user knows the task is in progress.&lt;/p&gt;

&lt;p&gt;Finally, we enable the Timer (with &lt;code&gt;self.timer_1.interval = 1&lt;/code&gt;), so that we can start checking every second to see whether our cluster has finished spinning up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you wanted to extend this app, you could add more UI elements to allow the user to set other parameters for their new cluster - for example, &lt;code&gt;n_workers&lt;/code&gt; or &lt;code&gt;scheduler_options&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the cluster has spun up, the Background Task that handles it will be completed. We can check for this using our Timer component. Every time our Timer ticks, we can inspect that Background Task objects and see if it's done yet.&lt;/p&gt;

&lt;p&gt;Here's some of the code that runs every time the Timer ticks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timer_1_tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is called every [interval] seconds. Does not trigger if [interval] is 0.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Check whether the setup task has completed
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task_running&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_completed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task_running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_calculations_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Your new cluster is ready!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code checks on the status of the &lt;code&gt;setup_task&lt;/code&gt;, and - if it's complete - the button to run calculations will be enabled. The Timer disables itself by setting its interval to &lt;code&gt;0&lt;/code&gt;, and sends an &lt;code&gt;alert&lt;/code&gt; (a pop-up) to give the user a very clear visual sign that they can now run their calculations.&lt;/p&gt;

&lt;p&gt;The button that says 'Run calculations' is now &lt;code&gt;enabled&lt;/code&gt;. When the user clicks it, we want to run the code that will connect to our new cluster and do the computation we want. Here's the event handler for the 'Run calculations' button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_calculations_button_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is called when the button is clicked&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;  
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;no_loading_indicator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;execute&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_task_running&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just as before, the event handler calls a server function to launch our second Background Task, and enables the Timer element. The Timer element should now also check for the status of the second task, so we'll add the following code to its event handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timer_1_tick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is called Every [interval] seconds. Does not trigger if [interval] is 0.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Check whether the setup task has completed
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task_running&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_completed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;# this is the code in the code block two sections above this one
&lt;/span&gt;
    &lt;span class="c1"&gt;# Check whether the plotting task has completed
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_task_running&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_completed&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="nf"&gt;open_form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ResultsForm&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_state&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;row&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the second Background Task is complete, we'll have some data to plot, so the Timer accesses that data with &lt;code&gt;self.plot_task.get_state()['row']&lt;/code&gt; and opens the &lt;code&gt;ResultsForm&lt;/code&gt; to display it. We'll take a look at the second Form later - but first, we'll need to generate that output data! Let's take a closer look inside that second Background Task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrangling some data
&lt;/h2&gt;

&lt;p&gt;This is the part that'll be familiar to anyone used to working with data: some computation. This app is just a demo, so we'll use Dask's built-in timeseries datasets. This function generates a dataset with one name per second over a set period of time, and using it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ddf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datasets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeseries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2000-01-01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2000-01-02&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;freq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that dataset exists, we use it to create two sets of output showing how many times each name appears in the dataset. For the first plot, we use the whole dataset, and for the second we take a random sample of 0.5% of the dataset.&lt;/p&gt;

&lt;p&gt;Once we've got each of those sets of output - that is, some x-values and y-values - we'll store them into a Data Table, called &lt;code&gt;output&lt;/code&gt;. It's best practice not to leave large amounts of data in the state of a Background Task, but we can store simple Python objects - like lists - in &lt;a href="https://anvil.works/blog/simple-object-storage" rel="noopener noreferrer"&gt;Simple Object&lt;/a&gt; columns in a Data Table. Then, we can retrieve that Data Table row from the Background Task's &lt;code&gt;state&lt;/code&gt; once the task has completed.&lt;/p&gt;

&lt;p&gt;Here's what the Data Table for storing our outputs looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Foutput-table.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Foutput-table.png" alt="A screenshot of a Data Table with two 'Simple Object' columns, one named 'total_counts' and one named 'random_sample'. Both columns are empty."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the code for calculating and storing the frequencies of all the names in our dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# create a new Data Table row to store our outputs
&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app_tables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_row&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# get the frequency for each name
&lt;/span&gt;&lt;span class="n"&gt;total_counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ddf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ddf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# store the x- and y-values as a list of lists in a Data Table
&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_counts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;total_counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# return this output in the Background Task's state
&lt;/span&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task_state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;row&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can do the same for a random sample of 0.5% of our dataset. And with that, the data wrangling is done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Plotting our data
&lt;/h2&gt;

&lt;p&gt;Now that we've got some output from our data in the form of two sets of x- and y-values, we want to display them to the end user. To do this, we'll build a second Form called &lt;code&gt;ResultsForm&lt;/code&gt; which will plot our output data, and display it to the user in the browser. This Form will also be used to &lt;a href="https://anvil.works/beta-docs/media/creating_pdfs" rel="noopener noreferrer"&gt;create a PDF version&lt;/a&gt; of the output, so the user can download and keep it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ResultsForm&lt;/code&gt; is visually very simple - just two &lt;a href="https://anvil.works/beta-docs/client/components/plots" rel="noopener noreferrer"&gt;Plots&lt;/a&gt;, a Label for each, and some buttons at the bottom for the user to either download this page as a PDF, or to return to the previous Form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Fresults-form.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fusing-coiled-with-anvil%2Fresults-form.png" alt="Two screenshots of the ResultsForm; on the left, it's empty as shown within the Anvil Editor. On the right, it's populated with data after the app has run."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left, you can see how the &lt;code&gt;ResultsForm&lt;/code&gt; looks in the Anvil Editor, and on the right you can see it populated with bar plots.&lt;/p&gt;

&lt;p&gt;This Form is loaded from the Timer element on our first form, the &lt;code&gt;StartupForm&lt;/code&gt;, after the computation task finishes, and at this point the output data is passed through to the &lt;code&gt;ResultsForm&lt;/code&gt;. So, when this new Form loads, we want it to use that output data to generate some plots, and we can write the code to do that in the &lt;code&gt;ResultsForm&lt;/code&gt;'s &lt;code&gt;__init__&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Anvil has &lt;a href="https://anvil.works/beta-docs/client/components/plots" rel="noopener noreferrer"&gt;client-side integration with Plotly&lt;/a&gt;, which means we can use &lt;a href="https://anvil.works/beta-docs/how-to/plot#plotly" rel="noopener noreferrer"&gt;&lt;code&gt;graph_objects&lt;/code&gt;&lt;/a&gt; to turn our output data into bar plots, and display those in the Form's Plot components. &lt;/p&gt;

&lt;p&gt;Here's some of the code that runs in the &lt;code&gt;ResultsForm&lt;/code&gt;'s &lt;code&gt;__init__&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...):&lt;/span&gt;
    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;plotly.graph_objects&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;

    &lt;span class="c1"&gt;# get the latest set of output data from our Data Table
&lt;/span&gt;    &lt;span class="n"&gt;total_plot_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_counts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_plot_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_plot_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;random_sample_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;random_sample&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random_plot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;go&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random_sample_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random_sample_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code uses the &lt;code&gt;row&lt;/code&gt; variable that was passed in from the calling code in the &lt;code&gt;StartupForm&lt;/code&gt;, and uses it to create bar plots which are displayed in the Plot components on the &lt;code&gt;ResultsForm&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating PDF output
&lt;/h2&gt;

&lt;p&gt;Anvil can &lt;a href="https://anvil.works/beta-docs/media/creating_pdfs" rel="noopener noreferrer"&gt;render any Form as a PDF&lt;/a&gt; and make it available for user download.  However, if we're rendering our &lt;code&gt;ResultsForm&lt;/code&gt; as a PDF, we don't necessarily want all the UI elements on it - such as the buttons - to be included. We want to have conditional formatting for the Form, depending on how it's being rendered.&lt;/p&gt;

&lt;p&gt;To make this happen, the &lt;code&gt;ResultsForm&lt;/code&gt; has an optional variable in its &lt;code&gt;__init__&lt;/code&gt; method, &lt;code&gt;as_pdf=False&lt;/code&gt;. We use this to optionally show various bits of the Form depending on whether it's being shown in the browser, or rendered as a PDF. This way, when we want to render the Form as a PDF, we can pass &lt;code&gt;as_pdf=True&lt;/code&gt;, and the Form can use that flag to hide any extraneous UI elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_pdf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="bp"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;as_pdf&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
      &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;return_button&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the Form is opened in the browser, &lt;code&gt;as_pdf&lt;/code&gt; will always be &lt;code&gt;False&lt;/code&gt;, so the buttons will show. When we create the PDF, we can set this variable to &lt;code&gt;True&lt;/code&gt;, hiding the buttons.&lt;/p&gt;

&lt;p&gt;Turning this Form into a PDF happens on the server side, in a function that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@anvil.server.callable&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PDFRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;quality&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;page_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Anvil Coiled Results.pdf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render_form&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ResultsForm&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# pass in the output data so the Form can generate its plots
&lt;/span&gt;    &lt;span class="bp"&gt;True&lt;/span&gt; &lt;span class="c1"&gt;# sets the `as_pdf` variable to `True`
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That function is called from the 'Download PDF' button's event handler in the browser, and the PDF is then downloaded. Here's that event handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pdf_button_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is called when the button is clicked&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;get_pdf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# self.row = row was set in the Form's __init__ method
&lt;/span&gt;    &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;media&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;To learn more about creating and downloading PDFs with Anvil, check out our feature guide &lt;a href="https://anvil.works/learn/tutorials/pdfs" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;And that's it! In this walkthrough, we've seen how to build an app that integrates with Coiled to let a user spin up a cluster and run computations with it. We've also seen how to build a flexible, extensible UI in Anvil, so that we can share this functionality by &lt;a href="https://anvil.works/beta-docs/deployment/quickstart" rel="noopener noreferrer"&gt;publishing our app&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Going even further
&lt;/h2&gt;

&lt;p&gt;This app is just a demo, showing the bare bones of how you can use Anvil to run Coiled code. In the real world, you'd be using a proper dataset, and likely allowing the end user to configure far more options for their clusters than just what's demonstrated here. You could have all sorts of different available computations, taking parameters from the users; you could make more use of &lt;a href="https://anvil.works/beta-docs/client/components/plots#handling-events" rel="noopener noreferrer"&gt;Plotly's interactivity&lt;/a&gt; on the front-end, and you could use Anvil's &lt;a href="https://anvil.works/docs/users" rel="noopener noreferrer"&gt;built-in user authentication&lt;/a&gt; to restrict actions like cluster provisioning to certain users. You could even store configuration options in a Data Table, and allow users to choose between multiple different Coiled profiles.&lt;/p&gt;

&lt;p&gt;If you do want to tinker with this for yourself, all you need to do is &lt;a href="https://anvil.works/build#clone:BRYOCOH7HDXDRGRZ=XSGJX2DUWANUJ3K2TWASQL5Z" rel="noopener noreferrer"&gt;clone this app&lt;/a&gt; into your own Anvil account, set your configuration details, and put your own Coiled API token into your app's Secrets. Have fun!&lt;/p&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/new-build" rel="noopener noreferrer"&gt;Try Anvil - it's free, forever.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>python</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Using custom Python packages with Anvil</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Thu, 24 Nov 2022 17:02:10 +0000</pubDate>
      <link>https://dev.to/anvil/using-custom-python-packages-with-anvil-31bd</link>
      <guid>https://dev.to/anvil/using-custom-python-packages-with-anvil-31bd</guid>
      <description>&lt;p&gt;&lt;a href="https://anvil.works/"&gt;Anvil&lt;/a&gt; is a platform for building web apps using nothing but Python, both on the &lt;a href="https://anvil.works/articles/client-vs-server"&gt;client and the server&lt;/a&gt;. This means that, with Anvil, you can create and deploy a web application without needing to learn HTML, JavaScript or CSS. Moreover, it means that Anvil developers can take advantage of Python's rich library of packages, and &lt;a href="https://anvil.works/beta-docs/client/ui"&gt;build a web interface&lt;/a&gt; that makes use of those packages.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you're completely new to Anvil, you might like to check out our &lt;a href="https://dev.to/learn/tutorials/feedback-form"&gt;Feedback Form tutorial&lt;/a&gt; - it'll walk you through the essentials of building an Anvil app!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can &lt;a href="https://anvil.works/beta-docs/server/custom-packages"&gt;install and use any Python package you like&lt;/a&gt; in your Anvil apps, either directly from PyPI, or any method supported by &lt;code&gt;pip&lt;/code&gt;'s &lt;a href="https://anvil.works/beta-docs/server/custom-packages#advanced-options"&gt;&lt;code&gt;requirements.txt&lt;/code&gt; file method&lt;/a&gt;. Packages you install are available in your app's &lt;a href="https://anvil.works/beta-docs/server"&gt;Server Modules&lt;/a&gt;, and can be used from client Python code in that app by making &lt;a href="https://anvil.works/beta-docs/server#calling-server-functions-from-client-code"&gt;server calls&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This tutorial will walk you through the process of building an Anvil app that uses custom packages, and by the end you'll know how to install and use any custom package you want in your Anvil apps.&lt;/p&gt;

&lt;p&gt;In this example tutorial, you'll build an app that generates and displays a word cloud based on the text of a random Wikipedia page. You'll use the &lt;a href="https://pypi.org/project/wikipedia/"&gt;wikipedia&lt;/a&gt;, &lt;a href="https://pypi.org/project/wordcloud/"&gt;wordcloud&lt;/a&gt; and &lt;a href="https://plotly.com/python/plotly-express/"&gt;Plotly Express&lt;/a&gt; packages to do this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To use custom packages in your Anvil apps, you'll need a &lt;a href="https://anvil.works/beta-docs/overview/free-vs-paid"&gt;Personal plan or above&lt;/a&gt;. If you're on a Free plan, you can get an instant 7 day trial, no credit card required - just follow this tutorial, and hit the Start Trial button when prompted!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's what you'll build:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ckrSeywN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/wikipedia.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ckrSeywN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/wikipedia.gif" alt="A GIF showing the finished app working." width="880" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This tutorial contains the following sections:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://anvil.works/learn/tutorials/using-custom-packages#step-1"&gt;Creating your Anvil app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/learn/tutorials/using-custom-packages#step-2"&gt;Importing packages into your server environment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/learn/tutorials/using-custom-packages#step-3"&gt;Generating word clouds from Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/learn/tutorials/using-custom-packages#step-4"&gt;Building your app's UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/learn/tutorials/using-custom-packages#step-5"&gt;Writing client Python code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1: Create your Anvil app
&lt;/h2&gt;

&lt;p&gt;First, you'll need to create your new app. To get started, head to the &lt;a href="https://anvil.works/new-build"&gt;Anvil Editor&lt;/a&gt;. On the landing page of the Editor, click 'Create a new app'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c8rkzcCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/new-blank-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c8rkzcCE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/new-blank-app.png" alt="A screenshot of the Anvil Editor's landing page, with the option to start from a new blank app or from a template." width="880" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose 'Blank app' from this screen., and from the dialog that appears, choose 'Material Design'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gXhv_s0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/material-design.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gXhv_s0c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/material-design.png" alt="A screenshot of the options for themes for an Anvil app." width="847" height="930"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll now see the Anvil Editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JOm-mUXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/beta-editor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JOm-mUXS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/beta-editor.png" alt="The Anvil Editor, showing a new blank app." width="880" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You are now editing a new, blank Anvil app, and you're ready to start building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Install packages into your app's server environment
&lt;/h2&gt;

&lt;p&gt;In order to use custom packages in your app's &lt;a href="https://anvil.works/beta-docs/server"&gt;Server Modules&lt;/a&gt;, you'll need to install them into the environment that your server code runs in. This step shows you how to do that.&lt;/p&gt;

&lt;p&gt;To &lt;a href="https://anvil.works/beta-docs/server/custom-packages"&gt;install custom packages&lt;/a&gt;, go to your App's Settings page. Select the gear icon from the &lt;a href="https://anvil.works/beta-docs/editor#sidebar-menu"&gt;Sidebar Menu&lt;/a&gt;, and you'll see this page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CduB1xQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/settings-page.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CduB1xQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/settings-page.png" alt="The Settings page for your app." width="880" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now select 'Python versions' from the options on the left, and then select 'Python 3.10' from the drop-down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mEBmjQ36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/docs/server/img/custom-packages/python-310.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mEBmjQ36--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/docs/server/img/custom-packages/python-310.png" alt="Selecting the Python 3.10 version for your app." width="880" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anvil provides &lt;a href="https://anvil.works/beta-docs/server/custom-packages#available-base-environments"&gt;several base environments&lt;/a&gt;, each of which has various packages pre-installed. You're going to start with the Data Science environment, then install three packages in addition.&lt;/p&gt;

&lt;p&gt;From the 'Base packages' section, choose 'Data Science' from the drop-down. Then, under the 'Package' section, add the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wikipedia&lt;/li&gt;
&lt;li&gt;wordcloud&lt;/li&gt;
&lt;li&gt;plotly-express&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each package, type its name as it appears above into the text box on the left, and leave the right-hand text box blank. Then, click the 'Add' button that appears, and you will be able to add another package. Here's how it will look as you add packages:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PcPCt4ob--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/add-packages.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PcPCt4ob--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/add-packages.gif" alt="A GIF showing the process of installing packages into your Anvil app's server environment." width="880" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, your packages are ready to use in your Anvil app's server environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Write a function to generate word clouds
&lt;/h2&gt;

&lt;p&gt;Now you've installed our libraries, it's time to write some code that uses them! Custom packages are available in &lt;a href="https://anvil.works/beta-docs/server"&gt;Server Modules&lt;/a&gt;, so you're going to write a server-side function to generate your word cloud. Then, in Step 4, you'll build a client-side user interface to call that server function and display the results.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to learn more about the structure of the web and the differences between Client and Server code, check out our &lt;a href="https://anvil.works/articles/client-vs-server"&gt;Client vs Server Code in Anvil&lt;/a&gt; article.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To add a Server Module to your app, go to the &lt;a href="https://anvil.works/beta-docs/editor#the-app-browser"&gt;App Browser&lt;/a&gt; by clicking the folder icon at the top of the &lt;a href="https://anvil.works/beta-docs/editor#sidebar-menu"&gt;Sidebar Menu&lt;/a&gt;. Then, under 'Server Code' on the left, click on &lt;a href="https://anvil.works/beta-docs/server/quickstart#add-a-server-module"&gt;&lt;code&gt;Add Server Module&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6RKOEKa---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/add-server-module.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6RKOEKa---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/add-server-module.png" alt="Adding a Server Module to your app." width="880" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the Python environment in which you can write your server function. At the top, add the following lines to import the packages you installed earlier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;wikipedia&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;wordcloud&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;WordCloud&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;plotly.express&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you're going to write a function that gets data from a random Wikipedia page, uses it to create a word cloud, and then returns that word cloud along with a link to the Wikipedia page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting a random Wikipedia page
&lt;/h3&gt;

&lt;p&gt;Here's the part where you'll write Python code to use your custom packages.&lt;/p&gt;

&lt;p&gt;You can get a title of a random Wikipedia page with the &lt;code&gt;wikipedia.random()&lt;/code&gt; function, as seen in the package's &lt;a href="https://wikipedia.readthedocs.io/en/latest/code.html"&gt;documentation&lt;/a&gt;. Once you have a title, you can get information about that page by calling the &lt;code&gt;wikipedia.page()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;So, to start, your function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_cloud&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, it's possible that the title returned by &lt;code&gt;wikipedia.random()&lt;/code&gt; might give you a &lt;a href="https://wikipedia.readthedocs.io/en/latest/code.html#wikipedia.exceptions.DisambiguationError"&gt;&lt;code&gt;DisambiguationError&lt;/code&gt;&lt;/a&gt; if you call &lt;code&gt;wikipedia.page()&lt;/code&gt; with it. This represents the 'Disambiguation' pages on Wikipedia (&lt;a href="https://en.wikipedia.org/wiki/Anvil_(disambiguation)"&gt;example&lt;/a&gt;). To avoid this, add code to retry the function call up to 5 times if that happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_cloud&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
      &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisambiguationError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you'll want to take that &lt;code&gt;text&lt;/code&gt; and use it to create a word cloud. Do this with the &lt;a href="https://amueller.github.io/word_cloud/generated/wordcloud.WordCloud.html"&gt;&lt;code&gt;WordCloud&lt;/code&gt;&lt;/a&gt; class you imported at the top of your Server Module.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;    &lt;span class="n"&gt;wordcloud&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WordCloud&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
python&lt;/p&gt;

&lt;p&gt;Now, you'll use Plotly Express to turn that &lt;code&gt;WordCloud&lt;/code&gt; object into something we can display.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="n"&gt;cloud&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wordcloud&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_xaxes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showticklabels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_yaxes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showticklabels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, this function needs to be able to be called from your app's client code, which we'll see in the next section. To make your function callable from the client, add the &lt;a href="https://anvil.works/beta-docs/server#calling-server-functions-from-client-code"&gt;&lt;code&gt;@anvil.server.callable&lt;/code&gt;&lt;/a&gt; decorator above the &lt;code&gt;def&lt;/code&gt; line.&lt;/p&gt;

&lt;p&gt;Your final function should now look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;callable&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_cloud&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
      &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;wikipedia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisambiguationError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;
  &lt;span class="n"&gt;wordcloud&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WordCloud&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cloud&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wordcloud&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_xaxes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showticklabels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_yaxes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showticklabels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you're ready to build your app's user interface!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Build your app's UI
&lt;/h2&gt;

&lt;p&gt;In this step, you'll use Anvil's &lt;a href="https://anvil.works/beta-docs/editor"&gt;drag-and-drop UI designer&lt;/a&gt; to &lt;a href="https://anvil.works/beta-docs/client/ui"&gt;build a user interface&lt;/a&gt; for your app. Every &lt;a href="https://anvil.works/beta-docs/client/components"&gt;component&lt;/a&gt; that you drag and drop onto your app's page is a Python object, with properties that you can set either from the designer itself, or by setting them in client code.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://anvil.works/beta-docs/editor#the-app-browser"&gt;App Browser&lt;/a&gt;, click on 'Form1' under 'Client Code'. This will open up your app's Form within the Editor, allowing you to start building your UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7gxs85Hc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/startup-form.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7gxs85Hc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/startup-form.png" alt="Editing the Startup Form for your app." width="880" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the right, you'll see the &lt;a href="https://anvil.works/beta-docs/editor#toolbox"&gt;Component Toolbox&lt;/a&gt;. You can drag and drop visual elements from the Toolbox onto your app's Form.&lt;/p&gt;

&lt;p&gt;To start, drag and drop a &lt;a href="https://anvil.works/beta-docs/client/components/basic#label"&gt;Label&lt;/a&gt; component into the Title slot on your Form. Click on it to bring up its &lt;a href="https://anvil.works/beta-docs/editor#properties-panel"&gt;Properties Panel&lt;/a&gt;, and change its &lt;code&gt;text&lt;/code&gt; property to "Wikipedia Word Clouds".&lt;/p&gt;

&lt;p&gt;Here's how that looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--msEkmVoV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/add-title.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--msEkmVoV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/add-title.gif" alt="A GIF showing the process of adding a component to your page and editing its properties." width="880" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Similarly, you're going to want to add a few other components on your app's Form:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drag a Card component into the main body of your Form.&lt;/li&gt;
&lt;li&gt;Within that Card, drop a &lt;a href="https://anvil.works/beta-docs/client/components/plots"&gt;Plot&lt;/a&gt; component.&lt;/li&gt;
&lt;li&gt;Drop a &lt;a href="https://anvil.works/beta-docs/client/components/basic#link"&gt;Link&lt;/a&gt; component below that, and change its &lt;code&gt;alignment&lt;/code&gt; to &lt;code&gt;center&lt;/code&gt; and its &lt;code&gt;font size&lt;/code&gt; to 40.&lt;/li&gt;
&lt;li&gt;Drag a Button component underneath your Card component, and change its &lt;code&gt;text&lt;/code&gt; property to &lt;code&gt;Give me a word cloud!&lt;/code&gt;, and its &lt;code&gt;role&lt;/code&gt; to &lt;code&gt;primary-color&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how that looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FtLSfntd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/add-card-ui.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FtLSfntd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/add-card-ui.gif" alt="A GIF showing the process of building the rest of your app's UI." width="880" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, set your Card's &lt;code&gt;visible&lt;/code&gt; property to &lt;code&gt;False&lt;/code&gt; by unchecking the box. Later, once we have a word cloud to display within it, we'll change this property from client code, making it visible again.&lt;/p&gt;

&lt;p&gt;Now, you're done with dragging and dropping components. It's time to write some client code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Writing client Python code
&lt;/h2&gt;

&lt;p&gt;In the last step, you built your UI. Now, you'll write some &lt;a href="https://anvil.works/docs/client/python"&gt;client-side Python code&lt;/a&gt; that will define how your UI behaves when a user interacts with it.&lt;/p&gt;

&lt;p&gt;Double-click on the Button at the bottom of your Form. This will take you to the code that drives your app's Form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--21T_3tvi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/code-view.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--21T_3tvi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/learn/tutorials/img/using-custom-packages/code-view.png" alt="An image showing how you can switch between the drag-and-drop Design view for your Form, the Code view for your Form, and a Split view by selecting an option in the top left of the  raw `Form1` endraw  tab in the Editor." width="880" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;button_1_click&lt;/code&gt; method has just been added to your Form's code; this method is called whenever a user clicks on the button. Modify it so that it calls your server function, &lt;code&gt;get_cloud&lt;/code&gt;, and uses the return values to change the UI elements on your Form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;button_1_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""This method is called when the button is clicked"""&lt;/span&gt;
    &lt;span class="n"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'get_cloud'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Give me another word cloud!"&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;card_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;visible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cloud&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, this method gets the word cloud, title and URL for a random wikipedia page, using the server function you wrote earlier. Then, the method does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;changes the text on the Button&lt;/li&gt;
&lt;li&gt;makes the Card (along with the Plot and Link) visible&lt;/li&gt;
&lt;li&gt;changes the Plot to display the word cloud&lt;/li&gt;
&lt;li&gt;changes the Link so that it links to the Wikipedia page, with the title of the page as its &lt;code&gt;text&lt;/code&gt; property&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's all the code you need to write! Click 'Run' in the top right of the Editor, click the button that says 'Give me a word cloud!', and watch your app generate a word cloud for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ckrSeywN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/wikipedia.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ckrSeywN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/learn/tutorials/wikipedia.gif" alt="A GIF showing the finished app working." width="880" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, you can &lt;a href="https://anvil.works/beta-docs/deployment-new-ide/quickstart"&gt;publish your app&lt;/a&gt; to make it available to anyone you like, by clicking the 'Publish' button in the top right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clone the App
&lt;/h2&gt;

&lt;p&gt;You can click the link below to clone the example app, and see how yours compares:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:RHTZSRVMKKORE7MZ%3dBWUEQSJ7CCMMQJNOLZ3OPJD2"&gt;Clone to your account&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;




&lt;h2&gt;
  
  
  New to Anvil?
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yes – Python that &lt;a href="https://anvil.works/docs/client/python"&gt;runs in the browser&lt;/a&gt;. Python that &lt;a href="https://anvil.works/docs/server"&gt;runs on the server&lt;/a&gt;. Python that &lt;a href="https://dev.to/docs/client"&gt;builds your UI&lt;/a&gt;. A &lt;a href="https://anvil.works/docs/client/ui"&gt;drag-and-drop UI editor&lt;/a&gt;. We even have a built-in &lt;a href="https://anvil.works/docs/data-tables"&gt;Python database&lt;/a&gt;, in case you don’t have your own.&lt;/p&gt;

&lt;p&gt;Why not have a play with the app builder? &lt;strong&gt;It's free!&lt;/strong&gt; Click here to get started:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/new-build"&gt;Get building!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Morse Code Generator with the Pico W</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Fri, 07 Oct 2022 15:35:35 +0000</pubDate>
      <link>https://dev.to/anvil/build-a-morse-code-generator-with-the-pico-w-3e</link>
      <guid>https://dev.to/anvil/build-a-morse-code-generator-with-the-pico-w-3e</guid>
      <description>&lt;h2&gt;
  
  
  Flash Morse Code Messages on the Pico W - with an interactive, secure, authenticated web app!
&lt;/h2&gt;

&lt;p&gt;This tutorial shows you how to create an Anvil app which takes a text input from a visitor, converts that text into Morse code, and makes your Pico W's LED flash with that Morse code message. It also shows you how to add &lt;a href="https://anvil.works/docs/users"&gt;user authentication&lt;/a&gt; to your app, so that you can control who has access to it.&lt;/p&gt;

&lt;p&gt;It consists of the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/morse-code#getting-started"&gt;Getting Started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/morse-code#show-morse-code"&gt;Showing Morse code on your Pico&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/morse-code#translating-text-into-morse-code"&gt;Translating text into Morse code in your app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/morse-code#build-ui"&gt;Building a user interface for your app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/morse-code#putting-it-all-together"&gt;Running the app to check that it works!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/morse-code#adding-user-authentication"&gt;Adding user authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;First, you'll need to get your Pico W running with the Anvil Uplink. Follow the &lt;a href="https://anvil.works/pico/get-started"&gt;Getting Started guide&lt;/a&gt;, then come back here when you're done!&lt;/p&gt;

&lt;h2&gt;
  
  
  Showing Morse code with your Pico's LED
&lt;/h2&gt;

&lt;p&gt;For this Morse Code tutorial, you'll be using a bigger Python environment than your Pico W, (&lt;a href="https://anvil.works/docs/server"&gt;in your Anvil app itself&lt;/a&gt;), to do the Morse conversion. Then, you'll call from code there to code running on your Pico so that the Pico only has to render the dots and dashes.&lt;/p&gt;

&lt;p&gt;Let's start with the code that will run on your Pico. Open up &lt;code&gt;main.py&lt;/code&gt; from your Pico, which should appear as a drive on your computer after installing the Anvil firmware.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YbVWeYKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/get-started/pico-as-flash-drive.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YbVWeYKY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/get-started/pico-as-flash-drive.png" alt="A screenshot of the Pico W mounted as a drive on a computer, now with the Anvil firmware installed and two files visible. The names of the files are boot.py and main.py." width="880" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how your Pico W will appear after you've installed the Anvil firmware. Open up the &lt;code&gt;main.py&lt;/code&gt; file. At the bottom of the file, you'll see this line of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pico&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UPLINK_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;no_led&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Directly above that, add the following code, which defines a function to make the LED on your Pico W blink fo a set duration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# We use the LED to display the message in Morse Code
&lt;/span&gt;&lt;span class="n"&gt;led&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Pin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OUT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;blink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration_ms&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;off&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, add the following function, which takes a Morse code string input and makes the LED of your Pico blink appropriately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pico&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callable_async&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;morse_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pico&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_user_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; has requested the message: '&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;blink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;blink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;anvil.pico.callable_async&lt;/code&gt; decorator means that this function will be callable from your Anvil app when your Pico is connected to the Uplink.&lt;/p&gt;

&lt;p&gt;Now, save and close this file, and reboot your Pico W.&lt;/p&gt;

&lt;h2&gt;
  
  
  Translating text into Morse code
&lt;/h2&gt;

&lt;p&gt;Next, you'll need to write the code that takes a text input and turns it into Morse code. This bit will be done in your Anvil app itself.&lt;/p&gt;

&lt;p&gt;In your Anvil app, open up your app's Structure view by clicking on the top icon on the left-hand sidebar. In the menu that pops out to the right, add a Server Module by clicking on the three-dots menu next to 'Server Code', and clicking 'Add Server Module'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jxW0Aiew--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/add-server-module.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jxW0Aiew--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/add-server-module.png" alt="A screenshot of the Anvil Editor showing how to add a new server module, as described in text immediately above." width="880" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will open up your new Server Module in the Editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q6JVMhB0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/fresh-server-module.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q6JVMhB0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/fresh-server-module.png" alt="A screenshot of a new server module in the Anvil Editor." width="880" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where you can write code that will run a full Python 3 environment, and it's where you're going to write the function that will turn text into Morse code.&lt;/p&gt;

&lt;p&gt;To do this, your app will need a way to translate text characters into Morse characters, which is a perfect job for a &lt;code&gt;dict&lt;/code&gt;. Add the following into your Server Module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MORSE_DICT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'C'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-.-.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'D'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-..'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'E'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'F'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'..-.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'G'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'--.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'H'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'....'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'I'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'..'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'J'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.---'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'K'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-.-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'L'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.-..'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'M'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'--'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'N'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'O'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'---'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'P'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.--.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Q'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'--.-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'R'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.-.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'S'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'T'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'U'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'..-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'V'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'...-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'W'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.--'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'X'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-..-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Y'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-.--'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Z'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'--..'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.----'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'2'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'..---'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'3'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'...--'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'4'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'....-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'5'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.....'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'6'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-....'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'7'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'--...'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'8'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'---..'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'9'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'----.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-----'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;', '&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'--..--'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'.-.-.-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'?'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'..--..'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-..-.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-....-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s"&gt;'('&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-.--.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;')'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;'-.--.-'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;' '&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dictionary will allow you to write a function which steps through a string, converting each character to Morse code as it goes. Here's a function which does just that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;morse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;MORSE_DICT&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;morse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you'll want to be able to call this function by clicking a button in your app's user interface, which means you need to &lt;a href="https://anvil.works/docs/server#calling-server-functions-from-client-code"&gt;make it &lt;strong&gt;callable&lt;/strong&gt; from the client&lt;/a&gt;. To do this, add the &lt;code&gt;anvil.server.callable&lt;/code&gt; decorator to your function, so that it looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;callable&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;morse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;MORSE_DICT&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;morse&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you're going to want this server function to call the &lt;code&gt;morse_message&lt;/code&gt; function on your Pico with the Morse code string it's generated. To do that, replace the &lt;code&gt;return&lt;/code&gt; statement with another &lt;code&gt;anvil.server.call&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;callable&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;display_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;morse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;MORSE_DICT&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'morse_message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;morse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building a user interface for your app
&lt;/h2&gt;

&lt;p&gt;In order for your app to take user input to display as Morse on your Pico W, it will need a user interface. In the Anvil Editor, open up &lt;code&gt;Form1&lt;/code&gt; from your app's structure menu:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CfcgiVyE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/open-form-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CfcgiVyE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/open-form-1.png" alt="A screenshot showing how to access your app's Form1 from the structure menu." width="880" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will open the web page you built as part of the Getting Started guide. So far, it only has a single button. Make sure you're using the Design view for your form:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TDJJksNZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/design-view-form.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TDJJksNZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/design-view-form.png" alt="he three buttons here allow you to see your Form with the drag-and-drop Editor, view the code that drives it, or see both in a split-screen view. To access the component toolbox, you need to be in Design view." width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Drag a &lt;a href="https://anvil.works/docs/client/components/basic#textbox"&gt;TextBox&lt;/a&gt; from the component toolbox on the right, and drop it above the button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RN794Fiy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/pico/drag-text-box.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RN794Fiy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/pico/drag-text-box.gif" alt="A GIF showing a user dragging and dropping a TextBox component onto the page." width="880" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To edit its properties - like its placeholder text, and the name of the Python object that represents it in client code - you can use the Properties panel on the right, below the component toolbox.&lt;/p&gt;

&lt;p&gt;In the above GIF, the Python name is being set to &lt;code&gt;self.txt_message&lt;/code&gt; and the placeholder text is being set to 'Type your message here!'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rJNX31Sl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/pico/edit-textbox-properties.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rJNX31Sl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/pico/edit-textbox-properties.gif" alt="A GIF showing someone editing the properties of their TextBox component from the Properties panel." width="880" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll see the changes appear on your Form as you alter the properties of your components.&lt;/p&gt;

&lt;p&gt;You can do the same thing with the button that's already on the page. Click it once, and the Properties panel will change to show the properties of the button, so that you can edit them. Set the 'text' property to 'Send message'.&lt;/p&gt;

&lt;p&gt;Now, double-click the button, and you'll be taken to the function that runs when the button is pressed. If you followed the Getting Started tutorial, this will already have some code in it. Change this function so that it calls the &lt;code&gt;display_message&lt;/code&gt; function in your Server Module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;button_1_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""This method is called when the button is clicked"""&lt;/span&gt;
    &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'display_message'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt_message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Your function's name might be different if you changed the Python name of the button component in the Properties panel.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it all together
&lt;/h2&gt;

&lt;p&gt;Now, click the 'Run' button in the top right of the Editor. Type in 'SOS' to your text box, click the 'Send message' button in your app, and watch the LED on your Pico W flash the Morse code!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding user authentication
&lt;/h2&gt;

&lt;p&gt;Now, you might not want just anyone having access to the ability to flash LEDs on your Pico. This section covers &lt;a href="https://anvil.works/docs/users"&gt;adding user authentication&lt;/a&gt; to your web app, so that only authorised users can enter text and have it sent as Morse code to your Pico.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding the Users Service
&lt;/h3&gt;

&lt;p&gt;Click the '&lt;code&gt;+&lt;/code&gt;' button in the lower left of the Editor to bring up the list of available services for your app, and select the Users service. This will bring up the configuration page for the Users Service in your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4Kqi6NaB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/docs/users/add-users-service.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4Kqi6NaB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/docs/users/add-users-service.gif" alt="A GIF showing someone adding the Users Service to an Anvil app." width="880" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From here, you can choose the possible &lt;a href="https://anvil.works/docs/users/authentication_choices"&gt;authentication methods&lt;/a&gt; for your users - such as email address and password, or single-sign-on with various providers like Google and Facebook. For now, leave the authentication method as 'Email + password'.&lt;/p&gt;

&lt;p&gt;Under 'New user registration', check the box that allows new visitors to sign up for an account, and uncheck the box that allows their accounts to be used right away. If you like, you can require your users to confirm an email address before their accounts can be activated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ofx54Hdx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/users-config.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ofx54Hdx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/users-config.png" alt="A screenshot of the Users Service page in the Anvil Editor, showing the configuration options described above." width="880" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This configuration lets new users sign up for accounts, but requires you (as the app's owner) to manually enable accounts before they can be used.&lt;/p&gt;

&lt;p&gt;Go to the code for 'Form1' by clicking on the 'Code' view button in the top left of the middle section of the Editor. Before, you've edited the code that runs when your button is pressed, but now you're going to add a line of code to your Form's &lt;code&gt;__init__&lt;/code&gt; method. This method runs whenever someone opens this Form - so, for example, when a user first visits your web app.&lt;/p&gt;

&lt;p&gt;Change the &lt;code&gt;__init__&lt;/code&gt; method so that you require users to log in when the Form first opens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Set Form properties and Data Bindings.
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;init_components&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Any code you write here will run when the form opens.
&lt;/span&gt;    &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;login_with_form&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Add this line here
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, click the 'Run' button in the top right of the Editor. You'll see a pop-up asking you to either log in or to sign up for a new account. Sign up for a new account using the email and password of your choice. If you've opted to require email confirmation, you'll need to do that before your account can be activated. Once you've done that, you should see a new row in the table at the bottom of the Users Service configuration page, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RQ4YyHO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/enable-user.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RQ4YyHO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/pico/img/morse-code/enable-user.png" alt="A screenshot of the table at the bottom of the Users Service page, showing a new row that has been created as a result of signing up for an account. The 'enabled' checkbox is unchecked." width="880" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll see that the 'enabled' checkbox is not yet checked, which means that you can't yet use this account to log in to your app. Check this box, and then click the 'Run' button again, and you will be able to use this account to log in. Then, you'll see the UI you previously built, and you can send messages to your Pico!&lt;/p&gt;

&lt;p&gt;Finally, if you want an extra layer of security, you can change the code in the &lt;code&gt;main.py&lt;/code&gt; file on your Pico W. Open it up, and add &lt;code&gt;require_user=True&lt;/code&gt; to the decorator on your &lt;code&gt;morse_message&lt;/code&gt; function, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pico&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callable_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;require_user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;morse_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that whenever a call is made to this function, Anvil will check that it came from an authenticated user in your web app. Save and close this file, then reboot your Pico.&lt;/p&gt;

&lt;p&gt;Now, go to the public URL for your app that you chose while &lt;a href="https://anvil.works/pico/get-started#publishing-your-app-on-the-web"&gt;publishing your app in the Getting Started tutorial&lt;/a&gt;. You'll be prompted to log in, which you can now do with the account you created and enabled, and you'll be able to enter a text message and see the Morse code flash on your Pico!&lt;/p&gt;

&lt;p&gt;And that's it! You've connected your Pico to a web app that takes user input and processes it, and uses the results to flash the LED on your Pico appropriately - &lt;em&gt;and&lt;/em&gt; you've made sure that it's only available to the users you choose.&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build"&gt;Try Anvil - it's free, forever.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>raspberrypi</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Pointers? In My Python? It's More Likely Than You Think - Part 3: Object Lifetimes and Garbage Collection</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Wed, 24 Aug 2022 14:57:33 +0000</pubDate>
      <link>https://dev.to/anvil/pointers-in-my-python-its-more-likely-than-you-think-part-3-object-lifetimes-and-garbage-collection-5hj9</link>
      <guid>https://dev.to/anvil/pointers-in-my-python-its-more-likely-than-you-think-part-3-object-lifetimes-and-garbage-collection-5hj9</guid>
      <description>&lt;p&gt;This is the third of a three-part series which covers various aspects of Python's memory management. It started life as a conference talk I gave in 2021, titled 'Pointers? In My Python?' and the most recent recording of it can be found &lt;a href="https://youtu.be/EMWKQt53rUQ?t=2760"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://anvil.works/articles/pointers-in-my-python-1"&gt;Part 1&lt;/a&gt; and &lt;a href="https://anvil.works/articles/pointers-in-my-python-2"&gt;Part 2&lt;/a&gt; of the series - or read on for an discussion of object lifetimes, reference counting, and garbage collection in CPython!&lt;/p&gt;

&lt;h2&gt;
  
  
  How CPython can tell when you're done with an object, and what happens next
&lt;/h2&gt;

&lt;p&gt;We ended Part 2 by asking the questions: once we've created an object &lt;code&gt;x&lt;/code&gt;, how and why does its 'lifetime' end? In this article, we'll learn the answers by exploring how CPython frees objects from memory. CPython isn't the only implementation of Python - for example, there's &lt;a href="https://skulpt.org/"&gt;Skulpt&lt;/a&gt;, which Anvil uses to &lt;a href="https://anvil.works/docs/client/python"&gt;run Python in the browser&lt;/a&gt; - but it's the one we'll focus on specifically for this article.&lt;/p&gt;

&lt;p&gt;We &lt;a href="https://anvil.works/articles/pointers-in-my-python-2#magic-methods"&gt;ended Part 2&lt;/a&gt; with an exploration of the weird and wonderful things that can happen when you override the &lt;code&gt;__eq__&lt;/code&gt; magic method in Python. Now, in Part 3, we're going to look at doing the same thing with a different magic method: &lt;code&gt;__del__&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;__del__&lt;/code&gt; magic method
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;__del__&lt;/code&gt; magic method, also called the &lt;strong&gt;finaliser&lt;/strong&gt; of an object, is a method that is called right before an object is about to be removed from memory. It doesn't actually do the work of removing the object from memory - we'll see how that happens later. Instead, this method is meant to be used to do any clean-up work that needs to happen before an object is removed - for example, closing any files that were opened by the object when it was created.&lt;/p&gt;

&lt;p&gt;We're going to be using the following class as an example throughout this section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__del__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Deleting &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just a class that'll let us know when one of its instances is about to be removed from memory - or, more specifically, when Python &lt;em&gt;expects&lt;/em&gt; to immediately remove the class instance from memory (this won't always be true, as we'll see!).&lt;/p&gt;

&lt;p&gt;In the above example, we've defined our class to take a &lt;code&gt;name&lt;/code&gt; input when initialised, and when the finaliser is called, it'll let us know by &lt;code&gt;print&lt;/code&gt;ing the &lt;code&gt;name&lt;/code&gt; of the instance in question. That way, we can get a bit of insight into which of these objects are being removed from memory, and when.&lt;/p&gt;

&lt;p&gt;So, when will CPython decide to remove an object from memory? There are (as of CPython 3.10) two ways this happens: &lt;strong&gt;Reference Counting&lt;/strong&gt; and &lt;strong&gt;Garbage Collection&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference counting in CPython
&lt;/h3&gt;

&lt;p&gt;If we have a pointer to an object in Python, that's a &lt;strong&gt;reference&lt;/strong&gt; to that object. For a given object &lt;code&gt;a&lt;/code&gt;, CPython keeps track of how many other things point at &lt;code&gt;a&lt;/code&gt;. If that counter reaches zero, it's safe to remove that object from memory, since nothing else is using it. Let's see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="n"&gt;Deleting&lt;/span&gt; &lt;span class="n"&gt;Jane&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create a new object (&lt;code&gt;MyNamedClass("Jane")&lt;/code&gt;) and create a pointer that points at it (&lt;code&gt;jane =&lt;/code&gt;). Then, when we &lt;code&gt;del jane&lt;/code&gt;, we remove that reference, and the &lt;code&gt;MyNamedClass&lt;/code&gt; instance now has a reference count of 0. So, CPython decides to remove it from memory - and, right before that happens, its &lt;code&gt;__del__&lt;/code&gt; method is called, which prints out the message we see above.&lt;/p&gt;

&lt;p&gt;If we create multiple references to an object, we'll have to get rid of all of them in order for the object to be removed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob_two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="c1"&gt;# creating a new pointer to the same object
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="c1"&gt;# this doesn't cause the object to be removed...
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;bob_two&lt;/span&gt; &lt;span class="c1"&gt;# ... but this does
&lt;/span&gt;&lt;span class="n"&gt;Deleting&lt;/span&gt; &lt;span class="n"&gt;Bob&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, our instances of &lt;code&gt;MyNamedClass&lt;/code&gt; could themselves contain pointers - after all, they're arbitrary Python objects, and we can add whatever attributes we like to them. Let's see an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="c1"&gt;# now the "Jane" object contains a pointer to the "Bob" object...
&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="c1"&gt;# ... and vice versa
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we've done in the above code snippet is set up some &lt;strong&gt;cyclic references&lt;/strong&gt;. The object whose &lt;code&gt;name&lt;/code&gt; is &lt;code&gt;Jane&lt;/code&gt; contains a pointer to the one whose &lt;code&gt;name&lt;/code&gt; is &lt;code&gt;Bob&lt;/code&gt;, and vice versa. Where this gets interesting is when we do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've now remove the pointers that go from the namespace to the objects. Now, we can't access those &lt;code&gt;MyNamedClass&lt;/code&gt; objects at all - but we didn't get the &lt;code&gt;print&lt;/code&gt; message telling us they're about to be deleted. This is because there are still references to these objects, contained within each other, and therefore their reference counts are not 0.&lt;/p&gt;

&lt;p&gt;What we've created here is a &lt;strong&gt;cyclic isolate&lt;/strong&gt;; a structure where each object has at least one reference within the cycle, keeping it alive, but none of the objects in the cycle can be accessed from the namespace.&lt;/p&gt;

&lt;p&gt;Below is a visual representation of what's going on when we create a cyclic isolate.&lt;/p&gt;

&lt;p&gt;To begin, we create our two objects, each of which also has a name in the namespace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cSZGTjjd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/pointers-in-my-python/017a-cyclic-isolate.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cSZGTjjd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/pointers-in-my-python/017a-cyclic-isolate.png" alt="A diagram showing the two Python objects 'bob' and 'jane', each with a pointer from the namespace, and each pointing to a string object" width="880" height="543"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we connect our two objects by adding a pointer from each to the other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--I3LDtloz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/pointers-in-my-python/017b-cyclic-isolate.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--I3LDtloz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/pointers-in-my-python/017b-cyclic-isolate.png" alt="'jane' and 'bob' now also contain a 'friend' attribute, which point to the other object" width="880" height="748"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we remove the pointers from the namespace by removing both of the original names for our objects. At this point, the two objects are inaccessible from the namespace, but each contains a pointer to the other so their reference counts are not zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NGrtlBvR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/pointers-in-my-python/017c-cyclic-isolate.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NGrtlBvR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/pointers-in-my-python/017c-cyclic-isolate.png" alt="The namespace pointers for 'jane' and 'bob' have been removed." width="880" height="1065"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, clearly, reference counting on its own isn't sufficient for keeping the working memory of your runtime free of useless, irretrievable objects. This is where CPython's &lt;strong&gt;Garbage Collector&lt;/strong&gt; comes in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Collecting garbage in CPython
&lt;/h2&gt;

&lt;p&gt;CPython's Garbage Collector (or GC for short) is Python's built-in way to get around the problem of cyclic isolates that we just encountered. By default, it's always running in the background, and it'll work its magic every now and then so you don't have to worry about cyclic isolates clogging up your memory.&lt;/p&gt;

&lt;p&gt;The garbage collector is designed to find and remove cyclic isolates from CPython's working memory. It does this in the following way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It detects cyclic isolates&lt;/li&gt;
&lt;li&gt;It calls the finalisers (the &lt;code&gt;__del__&lt;/code&gt; methods) on each object in the cyclic isolate&lt;/li&gt;
&lt;li&gt;It removes the pointers from each object (thus breaking the cycle) - &lt;em&gt;only if&lt;/em&gt; the cycle is still isolated after step 2 (more on this later!)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After this process is complete, every object that was previously in the cycle will now have a reference count of 0, and therefore will be removed from memory.&lt;/p&gt;

&lt;p&gt;Although it works automatically, we can actually import it &lt;a href="https://docs.python.org/3/library/gc.html"&gt;as a module&lt;/a&gt; from the standard library. Let's do that, so we can take an explicit look at how it works!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;gc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Detecting cyclic isolates
&lt;/h4&gt;

&lt;p&gt;CPython's garbage collector keeps track of various objects that exist in memory - but not &lt;em&gt;all&lt;/em&gt; of them. We can instantiate some objects and see whether the garbage collector &lt;a href="https://docs.python.org/3/library/gc.html#gc.is_tracked"&gt;cares about them&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_tracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a string"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_tracked&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an object can contain pointers, that gives it the ability to form part of a cyclic isolate structure - and &lt;em&gt;that's&lt;/em&gt; what the garbage detector exists to detect and dismantle. Such objects in Python are often called 'container objects'.&lt;/p&gt;

&lt;p&gt;So, the garbage collector needs to know about any object that has the potential to exist as part of a cyclic isolate. Strings can't, so &lt;code&gt;"a string"&lt;/code&gt; isn't tracked by the garbage collector. Lists (as we've seen) &lt;em&gt;are&lt;/em&gt; able to contain pointers, and therefore &lt;code&gt;['a', 'list']&lt;/code&gt; is tracked.&lt;/p&gt;

&lt;p&gt;Any instance of a user-defined class will also be tracked by the garbage collector, as we can always set arbitrary attributes (pointers) on them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_tracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jane&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, the garbage collector knows about all the objects that could potentially form a cyclic isolate. How does it know if one has formed? Well, it also &lt;a href="https://docs.python.org/3/library/gc.html#gc.get_referents"&gt;knows about all the pointers&lt;/a&gt; in each of those objects, and where they point. We can see this in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_referents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;get_referents&lt;/code&gt; method (also called a &lt;em&gt;traversal method&lt;/em&gt;) takes an object, and returns a list of the objects it contains pointers to (its &lt;em&gt;referents&lt;/em&gt;). So, the list above contains pointers to each of its elements, which are both strings.&lt;/p&gt;

&lt;p&gt;Let's take a look at the &lt;code&gt;get_referents&lt;/code&gt; method in the context of a cycle of objects (not yet a cyclic isolate, though, since these objects can still be accessed from the namespace):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_referents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'bob'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'friend'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyNamedClass&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7ff29a095d60&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyNamedClass&lt;/span&gt;&lt;span class="s"&gt;'&amp;gt;]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this cycle, we can see that the object pointed to by &lt;code&gt;bob&lt;/code&gt; contains pointers to the following: a dictionary of its attributes, containing &lt;code&gt;bob&lt;/code&gt;'s &lt;code&gt;name&lt;/code&gt; (&lt;code&gt;bob&lt;/code&gt;) and its &lt;code&gt;friend&lt;/code&gt; (the &lt;code&gt;MyNamedClass&lt;/code&gt; instance also pointed at by &lt;code&gt;jane&lt;/code&gt;). The &lt;code&gt;bob&lt;/code&gt; object also has a pointer to the class object itself, since &lt;code&gt;bob.__class__&lt;/code&gt; will return that class object.&lt;/p&gt;

&lt;p&gt;When the garbage collector runs, it checks whether every object it knows about (that is, anything that returns &lt;code&gt;True&lt;/code&gt; when you call &lt;code&gt;gc.is_tracked&lt;/code&gt; on it) is reachable from the namespace. It does this by following all the pointers from the namespace, and pointers within the objects that &lt;em&gt;those&lt;/em&gt; point to, as so on, until it &lt;a href="https://devguide.python.org/internals/garbage-collector/index.html#identifying-reference-cycles"&gt;builds up an entire view&lt;/a&gt; of everything that's accessible from code.&lt;/p&gt;

&lt;p&gt;If, after doing this, the GC finds that there exist objects which aren't reachable from the namespace, then it can &lt;a href="https://devguide.python.org/internals/garbage-collector/index.html#destroying-unreachable-objects"&gt;clear those objects up&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Remember, any objects that are still in memory must have a non-zero reference count, or else they'd have been removed due to reference counting. For objects to be unreachable and yet still have a non-zero reference count, they have to be part of a cyclic isolate, which is why we care so much about the possibility of these occurring.&lt;/p&gt;

&lt;p&gt;Let's return to our cycle of &lt;code&gt;friend&lt;/code&gt;s, &lt;code&gt;jane&lt;/code&gt; and &lt;code&gt;bob&lt;/code&gt;, and turn that cycle into a cyclic isolate by removing the pointers from the namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we've got ourselves into the exact situation that the garbage collector exists to fix. We can trigger manual garbage collection by calling &lt;a href="https://docs.python.org/3/library/gc.html#gc.collect"&gt;&lt;code&gt;gc.collect()&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Deleting&lt;/span&gt; &lt;span class="n"&gt;Bob&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;Deleting&lt;/span&gt; &lt;span class="n"&gt;Jane&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the garbage collector will perform this action automatically every so often (as more and more objects are created and destroyed within the CPython runtime).&lt;/p&gt;

&lt;p&gt;The output that we see in the code snippet above contains the &lt;code&gt;print&lt;/code&gt; statements from our &lt;code&gt;MyNamedClass&lt;/code&gt;'s &lt;code&gt;__del__&lt;/code&gt; method, and at the end there's a number - in this case, 4. This number is output from the garbage collector itself, and it tells us how many objects were removed.&lt;/p&gt;

&lt;p&gt;You might think that only 2 objects (our two &lt;code&gt;MyNamedClass&lt;/code&gt; instances) were removed, but each of them also pointed to a string object (their &lt;code&gt;name&lt;/code&gt;). Once those two &lt;code&gt;MyNamedClass&lt;/code&gt; instances are removed, the reference count for each of those &lt;code&gt;name&lt;/code&gt; strings also falls to zero, so they're removed too, bringing the total to 4 objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finalisers behaving badly
&lt;/h3&gt;

&lt;p&gt;Earlier, we mentioned that the garbage collector works in a 3-step process: detecting cyclic isolates, calling the finalisers on each object in the cycle, then breaking the cycle by removing the pointers between the objects... &lt;em&gt;if&lt;/em&gt; the cycle still remains isolated at this point. Now, the only way that the cycle could go from being isolated to not-isolated between the first and third step is if the finalisers do something to make that happen.&lt;/p&gt;

&lt;p&gt;Let's define a class that does just that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyBadClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__del__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="c1"&gt;# create an externally accessible pointer...
&lt;/span&gt;    &lt;span class="n"&gt;person&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt; &lt;span class="c1"&gt;# ... and point it at the object about to be removed
&lt;/span&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;deleting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;!”&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this class's finaliser, a &lt;strong&gt;global&lt;/strong&gt; variable is created. That means that even if an instance of &lt;code&gt;MyBadClass&lt;/code&gt; becomes inaccessible from the namespace (as part of a cyclic isolate, for example), it can still 'reach out' into the namespace, create a pointer there, and point that pointer at itself - thus de-isolating itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyBadClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyBadClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To see this in action, we set up the cyclic isolate structure, as we've done before with other (more well-behaved) classes. Then, we trigger garbage collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Deleting&lt;/span&gt; &lt;span class="n"&gt;Bob&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="n"&gt;Deleting&lt;/span&gt; &lt;span class="n"&gt;Jane&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see the print statements from each instance's &lt;code&gt;__del__&lt;/code&gt; method, but after that, the garbage collector prints us out a 0. That means that no objects were removed from memory - and that's because, after the garbage collector caused the finalisers to be called, it checked to make sure that the cycle was still isolated.&lt;/p&gt;

&lt;p&gt;If the cycle were still isolated, then the garbage collector could safely remove all the pointers linking up the objects, reducing their reference counter to 0. But, in this case, the cycle was no longer isolated, and so the garbage collector doesn't break the links between the objects in it.&lt;/p&gt;

&lt;p&gt;So, if we got rid of the &lt;code&gt;jane&lt;/code&gt; and &lt;code&gt;bob&lt;/code&gt; pointers, how can the cycle still be accessed from the namespace? The answer is that &lt;code&gt;global person&lt;/code&gt; variable that was created in the finaliser. Let's take a look at it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MyNamedClass&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7ff29a095d60&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="s"&gt;'Jane'&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;friend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="s"&gt;'Bob'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the object pointed to by &lt;code&gt;person&lt;/code&gt; is the same one that had previously been pointed to by &lt;code&gt;jane&lt;/code&gt;. This make sense if you look at the above output from calling &lt;code&gt;gc.collect()&lt;/code&gt;; the &lt;code&gt;print&lt;/code&gt; statement that appeared last was the one for the &lt;code&gt;Jane&lt;/code&gt; object, and therefore that was the object that set &lt;code&gt;person = self&lt;/code&gt; most recently.&lt;/p&gt;

&lt;p&gt;In other words, the two objects have had their original pointers &lt;code&gt;jane&lt;/code&gt; and &lt;code&gt;bob&lt;/code&gt; removed - but when their finalisers are called, a new &lt;em&gt;external&lt;/em&gt; pointer from the namespace is created, meaning that the cycle is no longer isolated and shouldn't be removed by the GC.&lt;/p&gt;

&lt;p&gt;Doing this sort of thing can create strange results, because it means you can access objects whose finalisers have already run -- and that probably means they've cleaned themselves up in a way that means you shouldn't be interacting with them again. For example, their finalisers may have closed a file that other methods on the object will assume to still be open. once again: overriding magic methods is serious business!&lt;/p&gt;

&lt;p&gt;So, does &lt;code&gt;MyBadClass&lt;/code&gt; break garbage collection entirely? The answer is no, and that's because of a very important property of finalisers: &lt;strong&gt;they can only be called once per object&lt;/strong&gt;. After &lt;code&gt;bob&lt;/code&gt;'s &lt;code&gt;__del__&lt;/code&gt; method has been called once (when it was triggered by the call to &lt;code&gt;gc.collect()&lt;/code&gt;), it's done, and can never be executed again. That means we can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't see the &lt;code&gt;"Deleting Jane"&lt;/code&gt; and &lt;code&gt;"Deleting Bob!"&lt;/code&gt; messages, because those are printed by the objects' finalisers - and those have already been called once, and can't be called again. But, since the &lt;code&gt;person&lt;/code&gt; pointer has been removed, the cycle is isolated again; and, because that &lt;code&gt;person&lt;/code&gt; pointer won't be recreated by a finaliser, the garbage collector can safely go ahead and remove the pointers linking our two &lt;code&gt;MyBadClass&lt;/code&gt; instances.&lt;/p&gt;

&lt;p&gt;Then the garbage collector continues its work, printing out a &lt;code&gt;4&lt;/code&gt; to let us know that those two objects and their &lt;code&gt;name&lt;/code&gt; attributes have been removed from memory - and all is well in the world (of our CPython interpreter, at least!) again!&lt;/p&gt;

&lt;h2&gt;
  
  
  So what have we learned?
&lt;/h2&gt;

&lt;p&gt;Let's recap! These three articles have been a whistle-stop tour of how Python handles objects in memory. We've looked at &lt;a href="https://anvil.works/articles/pointers-in-my-python-1#what-pointers-are"&gt;how pointers work&lt;/a&gt;, &lt;a href="https://anvil.works/articles/pointers-in-my-python-1#pointer-aliasing"&gt;why pointer aliasing happens&lt;/a&gt;, and whether you'll need  to use &lt;a href="https://anvil.works/articles/pointers-in-my-python-1#deepcopy"&gt;&lt;code&gt;=&lt;/code&gt;, &lt;code&gt;copy&lt;/code&gt; or &lt;code&gt;deepcopy&lt;/code&gt;&lt;/a&gt;. We've also seen &lt;a href="https://anvil.works/articles/pointers-in-my-python-2#object-ids"&gt;what object IDs are&lt;/a&gt; that &lt;a href="https://anvil.works/articles/pointers-in-my-python-2#is-uses-id"&gt;the &lt;code&gt;is&lt;/code&gt; comparator uses them&lt;/a&gt;,  and how we can override the &lt;code&gt;__eq__&lt;/code&gt; magic method to &lt;a href="https://anvil.works/articles/pointers-in-my-python-2#eq-method"&gt;define our own equality conditions&lt;/a&gt; to make &lt;code&gt;==&lt;/code&gt; do whatever we want. Finally, we've covered &lt;a href="https://anvil.works/articles/pointers-in-my-python-3#object-lifetimes"&gt;object lifetimes&lt;/a&gt;, the &lt;a href="https://anvil.works/articles/pointers-in-my-python-3#del-method"&gt;&lt;code&gt;__del__&lt;/code&gt; magic method&lt;/a&gt;, and how CPython frees objects from memory when they're not needed any more using &lt;a href="https://anvil.works/articles/pointers-in-my-python-3#reference-counting-in-cpython"&gt;reference counting&lt;/a&gt; and &lt;a href="https://anvil.works/articles/pointers-in-my-python-3#collecting-garbage-in-cpython"&gt;garbage collection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that you know all of these things, you can go forth and write better Python code!&lt;/p&gt;

&lt;h2&gt;
  
  
  See this article as a talk
&lt;/h2&gt;

&lt;p&gt;Various recorded versions of this talk are available at the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Nu6hy1Vgr90&amp;amp;list=PL8uoeex94UhFuRtXhkqOrROsdNI6ejuiq&amp;amp;index=97"&gt;EuroPython 2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=S0jcxqCVDvI"&gt;PyCon India 2021&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/EMWKQt53rUQ?t=2766"&gt;PyBerlin virtual meetup September 2021&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/new-build"&gt;Try Anvil - it's free, forever.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>computerscience</category>
      <category>memory</category>
    </item>
    <item>
      <title>Get Started with the Pico W</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Fri, 22 Jul 2022 14:58:24 +0000</pubDate>
      <link>https://dev.to/anvil/get-started-with-the-pico-w-1lfp</link>
      <guid>https://dev.to/anvil/get-started-with-the-pico-w-1lfp</guid>
      <description>&lt;h2&gt;
  
  
  Build your first internet-connected device
&lt;/h2&gt;

&lt;p&gt;This guide will show you how to take your brand new Pico W, connect it securely to the internet, and control it from from a web interface -- all in Python.&lt;/p&gt;

&lt;p&gt;We're going to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/pico/get-started#setting-up-your-pico-w" rel="noopener noreferrer"&gt;Set up your Pico W to use Anvil&lt;/a&gt;, by installing the Anvil firmware&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/pico/get-started#building-your-anvil-app" rel="noopener noreferrer"&gt;Build your web app&lt;/a&gt; with the Anvil&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/get-started#connecting-your-pico-w-to-your-web-app" rel="noopener noreferrer"&gt;Connect your Pico W to your web app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/get-started#updating-your-app-to-call-your-pico-w" rel="noopener noreferrer"&gt;Update your web app to call your Pico W from the web&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://anvil.works/pico/get-started#publishing-your-app-on-the-web" rel="noopener noreferrer"&gt;Publish your app on the web&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting up your Pico W
&lt;/h2&gt;

&lt;p&gt;To get your Pico W ready to use, you'll need to install the Anvil firmware. You'll only need to do this once.&lt;/p&gt;

&lt;p&gt;First, download the UF2 firmware file from &lt;a href="https://github.com/anvil-works/anvil-pico/releases/latest" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To install it onto your Pico W, you'll need to connect it to your computer via USB in &lt;strong&gt;firmware installation mode&lt;/strong&gt;, which allows you to install new firmware from files on your computer. To connect your Pico W in firmware installation mode, you'll need to hold down the BOOTSEL button as you plug it into your computer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fbootsel-button.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fbootsel-button.png" alt="A photo of a Pico W, with a red circle around the BOOTSEL button."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where the BOOTSEL button on your Pico W is.&lt;/p&gt;

&lt;p&gt;Once you've connected your Pico to your computer with the BOOTSEL button held down, it will appear as a drive on your computer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fmass-storage-mode-pico.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fmass-storage-mode-pico.png" alt="A screenshot of the Pico W mounted as a drive on a computer, in firmware installation mode."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how your Pico W will appear when it's in firmware installation mode.&lt;/p&gt;

&lt;p&gt;To install the Anvil firmware, copy the UF2 file you downloaded across to your Pico W. Once it's finished copying and processing, your Pico will automatically reboot and reappear again as a drive on your computer (perhaps with a different volume name). If you check what files are now inside, you'll see a &lt;code&gt;boot.py&lt;/code&gt; and a &lt;code&gt;main.py&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the USB drive doesn't appear, check out the &lt;a href="https://anvil.works/docs/uplink/pico#troubleshooting" rel="noopener noreferrer"&gt;Troubleshooting&lt;/a&gt; section of the reference docs for help.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpico-as-flash-drive.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpico-as-flash-drive.png" alt="A screenshot of the Pico W mounted as a drive on a computer, now with the Anvil firmware installed and two files visible. The names of the files are boot.py and main.py."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how your Pico W will appear after you've installed the Anvil firmware.&lt;/p&gt;

&lt;p&gt;That's it! You've now installed (or "flashed") the Anvil firmware onto your Pico W, and you're ready to start building.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building your Anvil app
&lt;/h2&gt;

&lt;p&gt;Next, you're going to build the web interface that's going to drive your Pico W. When you're done, you'll be able to click a button in this app and see lights flash on your Pico W!&lt;/p&gt;

&lt;p&gt;If you've tangled with web development before, this might sound daunting -- but don't worry. You're going to do it all in Python, with a drag-and-drop UI designer and an online editor at &lt;a href="https://anvil.works" rel="noopener noreferrer"&gt;anvil.works&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For now, all you need to do is create a new Anvil app and get an Uplink key to link it to your Pico.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an Anvil app
&lt;/h3&gt;

&lt;p&gt;Head to the &lt;a href="https://anvil.works/new-build" rel="noopener noreferrer"&gt;Anvil Editor&lt;/a&gt; to create a new app (you'll need an Anvil account for this - it's free!). On the landing page of the Editor, click 'Create a new app', then 'Blank app'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fnew-blank-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fnew-blank-app.png" alt="A screenshot of the Anvil Editor's landing page, with the option to start from a new blank app or from a template."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the dialog that appears, choose 'Material Design'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fmaterial-design.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fmaterial-design.png" alt="A screenshot of the options for themes for an Anvil app."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you'll now see before you is a new, blank Anvil app. For now, all we need to do is add the Uplink, which is how your app will communicate with your Pico. To do this, click the '&lt;strong&gt;&lt;code&gt;+&lt;/code&gt;&lt;/strong&gt;' icon in the lower left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fselect-new-service.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fselect-new-service.png" alt="A screenshot of the Anvil Editor, with the button to add new services highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the Uplink from the list:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fselect-uplink.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fselect-uplink.png" alt="A screenshot of the list of available services, with 'Uplink' highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the dialog box that appears, click 'Enable server Uplink'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fenable-server-uplink.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fenable-server-uplink.png" alt="A screenshot of the Uplink dialog box, with the 'Enable server Uplink' button highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That will generate an authentication key that you can copy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fuplink-key.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fuplink-key.png" alt="A screenshot of the Uplink dialog box, with the Uplink key section highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the Uplink key from that dialog box - you'll need it in a minute. (You can always bring this dialog back by clicking the 'Uplink' button in the top right of the Editor.)&lt;/p&gt;

&lt;p&gt;OK -- you now have a web app. It's time to connect your Pico to it!&lt;/p&gt;




&lt;h2&gt;
  
  
  Connecting your Pico W to your web app
&lt;/h2&gt;

&lt;p&gt;Connect your Pico W to your computer via USB (&lt;em&gt;don't&lt;/em&gt; hold down the BOOTSEL button this time!). As you've seen before, it will appear as a new drive, containing two &lt;code&gt;.py&lt;/code&gt; files: &lt;code&gt;boot.py&lt;/code&gt; and &lt;code&gt;main.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpico-as-flash-drive.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpico-as-flash-drive.png" alt="A screenshot of a Pico W mounted as a drive, with two Python files available within it called boot.py and main.py."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how your Pico W will look as a drive on your computer once the Anvil firmware has been installed.&lt;/p&gt;

&lt;p&gt;It's now time to edit those files to configure your app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding your WiFi network details into &lt;code&gt;boot.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;To let your Pico connect to the internet when it boots up, you'll need to give it your network details. Open up &lt;code&gt;boot.py&lt;/code&gt;, and at the very top you'll find a section where you can add these details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#############################################
# Provide your Wifi connection details here #
#############################################
&lt;/span&gt;
&lt;span class="n"&gt;WIFI_SSID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;put your network name here&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;WIFI_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;put your wifi password here&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;#############################################
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and close that file. Now, when your Pico W boots, it'll automatically connect to the network you provided.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding your Uplink key into &lt;code&gt;main.py&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In order for your Pico W to know about the Anvil app you just created, you'll need to give it your Uplink key. Open up &lt;code&gt;main.py&lt;/code&gt;: right underneath the &lt;code&gt;import&lt;/code&gt; statements you'll see the section where you can add your key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Replace this string with your Uplink key!
&lt;/span&gt;&lt;span class="n"&gt;UPLINK_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;put your Uplink key here&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit the code to use your app's real Uplink key. Now, when your Pico has booted and connected to the internet, it will be able to listen for input from your Anvil app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the &lt;code&gt;main.py&lt;/code&gt; file
&lt;/h3&gt;

&lt;p&gt;Your Uplink key isn't the only thing in &lt;code&gt;main.py&lt;/code&gt;. This is also where you can define functions that your Pico can run. To start with, there's a &lt;code&gt;pico_fn&lt;/code&gt; function, and all it does is toggle the LED on your Pico back and forth for a little bit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@anvil.pico.callable_async&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pico_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Output will go to the Pico W serial port
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Called local function with argument: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Blink the LED and then double the argument and return it.
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;led&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep_ms&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;anvil.pico.callable_async&lt;/code&gt; decorator lets your Anvil app know that this function is available to call from the web.&lt;/p&gt;

&lt;p&gt;Now, you're all set! Save your code, and reboot your Pico W. You'll see the LED flash slowly until the WiFi connects, then quickly while the connection to Anvil is established.&lt;/p&gt;

&lt;p&gt;You might want to connect to the USB serial device to see the Pico's output - see section 3.3 of &lt;a href="https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf" rel="noopener noreferrer"&gt;the Pico W documentation&lt;/a&gt; for more information.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When connecting to the serial port of the Pico W, the running Anvil firmware means that you sometimes won't see the MicroPython prompt automatically. Just hit Ctrl-C to stop whatever it's doing (such as failing to connect to the Wifi before you've added your credentials to &lt;code&gt;boot.py&lt;/code&gt;), and the prompt should appear.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Updating your app to call your Pico W
&lt;/h2&gt;

&lt;p&gt;Open up your Anvil app in the Anvil Editor. From the component toolbox on the right, drag and drop a Button component onto your page. For now, you don't need to worry about changing any of its properties.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil-website-static.s3.eu-west-2.amazonaws.com%2Fpico%2Fadd-button.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil-website-static.s3.eu-west-2.amazonaws.com%2Fpico%2Fadd-button.gif" alt="A GIF showing a button being dragged from the component toolbox to the page of the web app in the Anvil Editor."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, double click that button in the Editor, and you'll be taken to the new Python function that runs when that button is clicked. All you need to do is make that function call the function that's in your &lt;code&gt;main.py&lt;/code&gt; file on your Pico, and to do that, you use &lt;code&gt;anvil.server.call()&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;button_1_click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;event_args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;This method is called when the button is clicked&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;anvil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pico_fn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Choose any number you like!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil-website-static.s3.eu-west-2.amazonaws.com%2Fpico%2Fadd-function.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil-website-static.s3.eu-west-2.amazonaws.com%2Fpico%2Fadd-function.gif" alt="A GIF of someone double-clicking the button on the app page in the Anvil Editor, and being taken to the code which will run when that button is pressed."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, to see this in action, click the 'Run' button in the top right of the Editor. This will run your app, and if you now click the button, you'll see the LED on your Pico W flashing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil-website-static.s3.eu-west-2.amazonaws.com%2Fpico%2Frun-app-hit-button.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil-website-static.s3.eu-west-2.amazonaws.com%2Fpico%2Frun-app-hit-button.gif" alt="A GIF of the app being run from the Anvil Editor, and the button within it being clicked."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've successfully called a function on your Pico from your web app!&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing your app on the web
&lt;/h2&gt;

&lt;p&gt;The very last step is make your app available on the public web. To do this, click the 'Publish' button in the top right of the Editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpublish-button.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpublish-button.png" alt="A screenshot of the Anvil Editor, with the 'publish' button in the top right highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click 'Publish this app' in the next dialog box:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpublish-app-dialog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fpublish-app-dialog.png" alt="A screenshot of the 'Publish' dialog box, with 'Publish this app' highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it -- your app is online!&lt;/p&gt;

&lt;p&gt;Anvil automatically generates a URL for your app, but you can choose a different one in the dialog box with the 'Change URL' button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fchoose-url.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fpico%2Fimg%2Fget-started%2Fchoose-url.png" alt="A screenshot of the 'Publish' dialog box, with the URL section highlighted in orange."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose a snappy URL for your app - or let Anvil generate one for you.&lt;/p&gt;

&lt;p&gt;Once you've done this, you can open that URL from anywhere in the world -- your computer, your phone, Australia. Click the button, and make the LED on your Pico flash!&lt;/p&gt;

&lt;h2&gt;
  
  
  Go even further
&lt;/h2&gt;

&lt;p&gt;Now that you've connected your Pico W securely to the web with Anvil, you can build whatever you want.&lt;/p&gt;

&lt;p&gt;As a first project, let's make your Pico's LED flash Morse code messages entered from a web page! Here's a step-by-step tutorial:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://anvil.works/pico/morse-code" rel="noopener noreferrer"&gt;Build a Morse Code Generator&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Or, if you're ready to dive into your own projects, you can read about some of the &lt;a href="https://dev.toadvanced"&gt;more advanced things&lt;/a&gt; you can do with Anvil on your Pico W, or consult our &lt;a href="https://anvil.works/docs/uplink/pico" rel="noopener noreferrer"&gt;reference documentation&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build" rel="noopener noreferrer"&gt;Try Anvil - it's free, forever.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pico</category>
      <category>raspberrypi</category>
      <category>iot</category>
      <category>python</category>
    </item>
    <item>
      <title>Pointers? In My Python? It's More Likely Than You Think - Part 2: Equality</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Thu, 30 Jun 2022 13:00:15 +0000</pubDate>
      <link>https://dev.to/anvil/pointers-in-my-python-its-more-likely-than-you-think-part-2-equality-1f9c</link>
      <guid>https://dev.to/anvil/pointers-in-my-python-its-more-likely-than-you-think-part-2-equality-1f9c</guid>
      <description>&lt;p&gt;This is the second of a three-part series which covers various aspects of Python's memory management. It started life as a conference talk I gave in 2021, titled 'Pointers? In My Python?' and the most recent recording of it can be found &lt;a href="https://youtu.be/EMWKQt53rUQ?t=2760"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out &lt;a href="https://anvil.works/articles/pointers-in-my-python-1"&gt;Part 1&lt;/a&gt; of the series, or read on for an discussion of Object IDs in Python!&lt;/p&gt;

&lt;h2&gt;
  
  
  Object IDs, and why they matter
&lt;/h2&gt;

&lt;p&gt;We ended Part 1 with the following question: how do we know when two Python objects are &lt;em&gt;really&lt;/em&gt; the same object in memory? If we do &lt;code&gt;b = deepcopy(a)&lt;/code&gt;, how can we know for sure that it didn't just create a new pointer instead of a whole new object? The answer is &lt;strong&gt;Object IDs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Python has a built-in &lt;code&gt;id&lt;/code&gt; function with the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id(x)&lt;/code&gt; is an integer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id(x) != id(y)&lt;/code&gt; exactly when &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; point at different objects in memory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id(x)&lt;/code&gt; is constant for the &lt;strong&gt;lifetime&lt;/strong&gt; of &lt;code&gt;x&lt;/code&gt; - that is, as long as &lt;code&gt;x&lt;/code&gt; remains in memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many implementations of Python, and while the above three things must be true of the &lt;code&gt;id&lt;/code&gt; function in each of them, they don't all do it in the same way under the hood. Some implementations, such as CPython (the python interpreter written in C), use the object's memory address as its &lt;code&gt;id&lt;/code&gt; - but don't assume that all implementations will!&lt;/p&gt;

&lt;p&gt;For example, Skulpt is the Python-to-JavaScript compiler which Anvil uses to run &lt;a href="https://anvil.works/docs/client/python"&gt;Python client code&lt;/a&gt; in the browser so you can develop for the web without having to write JavaScript; Skulpt's implementation of &lt;code&gt;id&lt;/code&gt; generates and caches a random number for every object in memory.&lt;/p&gt;

&lt;p&gt;For the rest of this article, we'll be using examples generated using CPython, which equates an object's &lt;code&gt;id&lt;/code&gt; with its address in memory.&lt;/p&gt;

&lt;p&gt;So, let's look at what happens when we check an object's &lt;code&gt;id&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;139865338256192&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;139865338256192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;139865338256192&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we've defined a list &lt;code&gt;a&lt;/code&gt;, and created a new pointer to it by setting &lt;code&gt;b = a&lt;/code&gt;. When we check their &lt;code&gt;id&lt;/code&gt;s, we can see that they're the same - &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; point to the same thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;139865338256192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;139865337919872&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trying the same thing with &lt;code&gt;c = a.copy()&lt;/code&gt; shows that this creates a new list object; &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;c&lt;/code&gt; have different &lt;code&gt;id&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;However, that isn't the only notion of 'sameness' that Python provides. Consider our familiar example, with &lt;code&gt;a&lt;/code&gt; pointing to a list object list, &lt;code&gt;b&lt;/code&gt; another pointer to that object, and &lt;code&gt;c&lt;/code&gt; a pointer to a copy of that object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"my"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"list"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, we can do the following comparisons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again: what is going on here? How can two things be the same and not the same? The answer is that &lt;code&gt;is&lt;/code&gt; and &lt;code&gt;==&lt;/code&gt; are designed to serve two different purposes. &lt;code&gt;is&lt;/code&gt; is for when you want to know if two pointers are pointing at the exact same object in memory; &lt;code&gt;==&lt;/code&gt; is for when you want to know if two objects should be &lt;em&gt;considered&lt;/em&gt; to be equal.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;is&lt;/code&gt; uses &lt;code&gt;id(x)&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Saying &lt;code&gt;a is b&lt;/code&gt; is directly equivalent to saying &lt;code&gt;id(a) == id(b)&lt;/code&gt;. When you call &lt;code&gt;is&lt;/code&gt; on two objects, Python takes their &lt;code&gt;id&lt;/code&gt;s and directly compares them.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;==&lt;/code&gt; uses &lt;code&gt;__eq__&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When you write &lt;code&gt;a == b&lt;/code&gt;, you're actually calling a &lt;strong&gt;magic method&lt;/strong&gt;, also known as a &lt;strong&gt;dunder method&lt;/strong&gt; (named for the &lt;strong&gt;d&lt;/strong&gt;ouble-&lt;strong&gt;under&lt;/strong&gt;score on each side). You might be familiar with some magic methods already, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;__init__&lt;/code&gt;, called when an instances of a Python class is initialised&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__str__&lt;/code&gt;, called when you use the &lt;code&gt;str&lt;/code&gt; built-in - e.g. &lt;code&gt;str(some_object)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;__repr__&lt;/code&gt;, similar to &lt;code&gt;__str__&lt;/code&gt; but also called in other circumstances such as error messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Magic methods are simply methods on a Python class, and the double underscores indicate that they interact with built-in Python methods. For example, overwriting the &lt;code&gt;__str__&lt;/code&gt; method on a Python class would change how the &lt;code&gt;str&lt;/code&gt; built-in behaved if you called it on an instance of that modified class.&lt;/p&gt;

&lt;p&gt;When it comes to &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;__eq__&lt;/code&gt;, it's easiest to understand with some examples. Let's dive in!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__eq__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we've defined a custom class with its own &lt;code&gt;__eq__&lt;/code&gt; method. Every &lt;code&gt;__eq__&lt;/code&gt; method takes two arguments including &lt;code&gt;self&lt;/code&gt; - because whenever it's called, it'll be comparing two objects, including the instance of the class in question. In the above example, we've just set the method to fall through to the &lt;code&gt;is&lt;/code&gt; definition of equality (comparing the &lt;code&gt;id&lt;/code&gt;s of each object). As it happens, this is actually the default behaviour for any user-defined class in Python.&lt;/p&gt;

&lt;p&gt;So, what happens if we define some non-default behaviour?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAlwaysTrueClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__eq__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we've defined a class which takes a &lt;code&gt;name&lt;/code&gt; argument (so we can keep track of our instances!) and has an &lt;code&gt;__eq__&lt;/code&gt; method which indiscriminately returns &lt;code&gt;True&lt;/code&gt;. This gives us the following behaviour:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyAlwaysTrueClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyAlwaysTrueClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because we overrode the &lt;code&gt;__eq__&lt;/code&gt; method to &lt;em&gt;always&lt;/em&gt; return &lt;code&gt;True&lt;/code&gt;, that means that all instances of this class will be considered equal under the &lt;code&gt;==&lt;/code&gt; comparator - even when their names have different values!&lt;/p&gt;

&lt;p&gt;Conversely, we can also do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyAlwaysFalseClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__eq__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might think this is more sensible, but consider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyAlwaysFalseClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moreover, because the behaviour of &lt;code&gt;__eq__&lt;/code&gt; is dependent on which object is &lt;code&gt;self&lt;/code&gt; and which is &lt;code&gt;other&lt;/code&gt;, we can get the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyAlwaysTrueClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MyAlwaysFalseClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt;
&lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bob&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;jane&lt;/span&gt;
&lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary: magic methods are a fun way to make Python do things that seem very strange.&lt;/p&gt;




&lt;p&gt;Earlier, we mentioned that &lt;code&gt;id(x)&lt;/code&gt; is constant and unique 'for the lifetime of &lt;code&gt;x&lt;/code&gt;', which is equivalent to saying 'as long as &lt;code&gt;x&lt;/code&gt; remains in memory'. That raises the question: once we've created an object &lt;code&gt;x&lt;/code&gt;, how does its 'lifetime' end? Hold on 'til Part 3 of this series, where we'll get the answer!&lt;/p&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build"&gt;Try Anvil - it's free forever!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>memory</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Building A Python Code Completer at PyCon US 2022</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Thu, 26 May 2022 14:23:47 +0000</pubDate>
      <link>https://dev.to/anvil/building-a-python-code-completer-at-pycon-us-2022-158b</link>
      <guid>https://dev.to/anvil/building-a-python-code-completer-at-pycon-us-2022-158b</guid>
      <description>&lt;p&gt;Almost all of Anvil went to PyCon US in Salt Lake City this past April, and we had a blast. To round off the trip, we were able to watch Meredydd give his first in-person talk at a US PyCon - and it was awesome. Even better, the recordings are now out, so you can see it for yourselves!&lt;/p&gt;

&lt;p&gt;In his talk, Meredydd teaches us how Python parses and compiles code, what an AST is, and how we can use this knowledge to work out what a programmer might type next. And, to prove it’s not that complicated, he builds a little code completer, live on stage, in about five minutes.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/aRO7DkJrA_c"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you’re new here, welcome! &lt;a href="https://anvil.works"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just build it all in Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build"&gt;Try Anvil - it's free, forever.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>ux</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Pointers? In My Python? It's More Likely Than You Think</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Mon, 23 May 2022 14:56:22 +0000</pubDate>
      <link>https://dev.to/anvil/pointers-in-my-python-its-more-likely-than-you-think-2dfn</link>
      <guid>https://dev.to/anvil/pointers-in-my-python-its-more-likely-than-you-think-2dfn</guid>
      <description>&lt;p&gt;This is the first of a three-part series, covering various aspects of Python's memory management; it started life as a conference talk I gave in 2021, titled 'Pointers? In My Python?', the most recent recording of which can be found &lt;a href="https://youtu.be/EMWKQt53rUQ?t=2760" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tour of Python's memory magic
&lt;/h2&gt;

&lt;p&gt;Python is a wonderful thing that takes all the complication of memory management away from us. We don’t have to worry about pre-allocating memory for our objects, or remember to free it once we’re done. So, given that we’re not doing it manually, how do these things happen? Do we have to care? Well, sometimes. Maybe.&lt;/p&gt;

&lt;p&gt;For example, ever wondered about the difference between &lt;code&gt;is&lt;/code&gt; and &lt;code&gt;==&lt;/code&gt;, or why you might need to use &lt;code&gt;deepcopy&lt;/code&gt;? Maybe you’ve been stumped by a variable changing when you didn’t expect it to, or an interview question about object lifetimes. Or, perhaps, you just really want to see some tuples behaving badly. This three-part series answers all these questions and more, covering the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 1: what a pointer is, and where you'll see them in Python&lt;/li&gt;
&lt;li&gt;Part 2: what the &lt;code&gt;id&lt;/code&gt; of a Python object is, and why it matters&lt;/li&gt;
&lt;li&gt;Part 3: how CPython can tell when you're done using an object in memory, and what it does next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's dive in with Part 1!&lt;/p&gt;

&lt;h2&gt;
  
  
  What pointers are, and where you'll find them
&lt;/h2&gt;

&lt;p&gt;Firstly, we need to understand the concept of a &lt;em&gt;namespace&lt;/em&gt;. A namespace in Python is the list of all the variables, keywords and functions that are in scope at any given point - that is, things you can write that the Python interpreter will understand. For example, all the built-in functions like &lt;code&gt;print()&lt;/code&gt; and &lt;code&gt;str()&lt;/code&gt;, and keywords like &lt;code&gt;None&lt;/code&gt; and &lt;code&gt;True&lt;/code&gt; are always in every namespace.&lt;/p&gt;

&lt;p&gt;When you create a new variable, then that variable's name is added to the namespace of whichever &lt;a href="https://realpython.com/python-namespaces-scope/" rel="noopener noreferrer"&gt;scope&lt;/a&gt; it's in. So, for example, writing the following will add the name &lt;code&gt;my_string&lt;/code&gt; to the global namespace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello World!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the purposes of this series of articles, we don't need to worry about scopes; we can assume all our examples take place in the global namespace.&lt;/p&gt;

&lt;p&gt;Pointers can be thought of as names - that is, entries in Python's &lt;em&gt;namespace&lt;/em&gt; - that correspond to objects in Python's &lt;em&gt;memory&lt;/em&gt;. In the above example, the pointer is &lt;code&gt;my_string&lt;/code&gt;, and the object in memory is the string with value &lt;code&gt;"Hello World!"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By using a pointer in namespace, you can access and manipulate the object in memory. And, just as a person might have multiple names, multiple pointers might point to the same object.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A note about terminology: the 'pointers' referred to in this article are not directly equivalent to pointers in C or C++ (in fact, they're more similar to references in C++). For those brave souls who code in C, an excellent breakdown of the minutiae can be found &lt;a href="https://realpython.com/pointers-in-python/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As an example, let's consider a &lt;code&gt;list&lt;/code&gt; object with the name &lt;code&gt;my_list&lt;/code&gt; and two arbitrary elements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F003-anatomy-of-a-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F003-anatomy-of-a-list.png" alt="A diagram showing a list with two elements, one a string with value  raw `string` endraw  and one an integer with value 42."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That name &lt;code&gt;my_list&lt;/code&gt; then points to the &lt;code&gt;list&lt;/code&gt; object. That &lt;code&gt;list&lt;/code&gt; object then contains pointers to the two objects which are the elements of that list. So, when you create a list, it will automatically contain pointers if it has any elements. For that reason, we'll be using a lot of lists as examples throughout this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pointer aliasing
&lt;/h3&gt;

&lt;p&gt;One Python behaviour that often trips up a lot of beginners is something called &lt;em&gt;pointer aliasing&lt;/em&gt;, which is when two pointers refer to the same object in memory. Let's look at an example: a list containing some strings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]
&lt;/span&gt;&lt;span class="gp"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we've defined our list &lt;code&gt;a&lt;/code&gt; and got our interpreter to print it back out for us, just to check that it is as we expect. Next, we (naively) try to make a copy, and make some changes to it, namely changing &lt;code&gt;"string"&lt;/code&gt; to &lt;code&gt;"some words"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some words&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some words&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Except, it turns out we've &lt;em&gt;also&lt;/em&gt; changed our original list &lt;code&gt;a&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some words&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The common misconception here is that &lt;code&gt;a&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; the list object, when it's actually just pointing at it, and might not be the only that that points at it. What's happened above is that, in the line where we set &lt;code&gt;b = a&lt;/code&gt;, we didn't actually make a new list object. We just created a new pointer, &lt;code&gt;b&lt;/code&gt;, and made it point to the same underlying list object that &lt;code&gt;a&lt;/code&gt; already pointed to.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006a-comparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006a-comparison.png" alt="Using  raw `=` endraw  on its own simply creates a new pointer to the same object - a simple pointer alias."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006a-comparison-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006a-comparison-2.png" alt="So, when we change  raw `b[0]` endraw , we change  raw `a[0]` endraw  too."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, when we change &lt;code&gt;b&lt;/code&gt;, we're changing &lt;code&gt;a&lt;/code&gt; too. But what if we did want to make a new list object, and be able to make changes to it without affecting the original? Well, there's a list method for that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some words&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use the &lt;code&gt;copy&lt;/code&gt; method on our original list object, and this &lt;em&gt;does&lt;/em&gt; create a new list object. That new list object will also contain new pointers - &lt;em&gt;but&lt;/em&gt;, those pointers will then point to the same underlying elements of the original list. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006b-comparison.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006b-comparison.png" alt="A diagram showing the effect of using the  raw `copy` endraw  method to create a new list object."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;copy&lt;/code&gt; (whether as a list method or as a function from within &lt;a href="https://docs.python.org/3/library/copy.html" rel="noopener noreferrer"&gt;the &lt;code&gt;copy&lt;/code&gt; module&lt;/a&gt;) creates a new object, and populates it with new pointers to the existing elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006b-comparison-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2F006b-comparison-2.png" alt="So, when we change  raw `c[0]` endraw , we're _only_ changing that, and not  raw `a[0]` endraw ."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The outer list object - the thing that also has access to list methods, and which &lt;em&gt;contains&lt;/em&gt; pointers to its contents, is different - but with &lt;code&gt;copy&lt;/code&gt;, the elements of each list will still be the same objects in memory. So, what if those elements are themselves lists?&lt;/p&gt;

&lt;p&gt;Let's define a new list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alex&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alex&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a visual representation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fnested-lists-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fnested-lists-1.png" alt="Here we have an outer list  raw `a` endraw  whose only element is itself another list with two elements."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's do as we did before, and make a new list object using the &lt;code&gt;copy&lt;/code&gt; method. This time though, we'll append something to the first &lt;em&gt;element&lt;/em&gt; of &lt;code&gt;b&lt;/code&gt;, not &lt;code&gt;b&lt;/code&gt; itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charlie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alex&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charlie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fnested-lists-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fnested-lists-2.png" alt="When we use  raw `copy` endraw , it creates a new outer list object in memory."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, so good, right? Except....&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alex&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charlie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... we managed to alter the contents of &lt;code&gt;a&lt;/code&gt;, even though we used the &lt;code&gt;copy&lt;/code&gt; method. This is because, as stated above, the pointers in &lt;code&gt;b&lt;/code&gt; still point at the same contents as the original list - so, we get the same pointer aliasing behaviour as we saw in the very first example, just one layer deeper. This kind of copy (only creating new objects one level deep, and pointer aliasing the rest) is called a 'shallow copy'.&lt;/p&gt;

&lt;p&gt;So, if we want to make a true, 'deep' copy -  that is, to make not only a new list object, but new versions of all its contents - how do we do that? The answer is &lt;code&gt;deepcopy&lt;/code&gt;, a function within the &lt;code&gt;copy&lt;/code&gt; module of the standard library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;copy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deepcopy&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deepcopy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alex&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charlie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alex&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;beth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;charlie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What &lt;code&gt;deepcopy&lt;/code&gt; does is recursively create new versions of every object it encounters - so, when it's called on our list &lt;code&gt;a&lt;/code&gt;, it'll create a new list, and when it sees that the elements of &lt;code&gt;a&lt;/code&gt; also contain pointers themselves, it'll make new copies of the things those pointers point to as well. (Try saying that three times fast with a mouthful of spaghetti.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fnested-lists-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fnested-lists-3.png" alt="A diagram showing nested lists."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;deepcopy&lt;/code&gt; creates a whole new inner list, complete with new contents. So, when we mutate the inner list of &lt;code&gt;c&lt;/code&gt;, it's not touching the &lt;em&gt;original&lt;/em&gt; inner list that &lt;code&gt;a&lt;/code&gt; points at - because &lt;code&gt;deepcopy&lt;/code&gt; made a new, separate copy of that list when it created &lt;code&gt;c&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this particular scenario, we're using strings as the contents of our inner lists. That means that technically the &lt;code&gt;alex&lt;/code&gt; string pointed to by &lt;code&gt;a[0][0]&lt;/code&gt; is also the same object in memory as the one pointed to by &lt;code&gt;c[0][0]&lt;/code&gt;, because Python has some memory optimisations that prevent it from creating the same immutable object twice if it doesn't need to. If we'd used - for example - a user-defined class object instead of strings, then &lt;code&gt;deepcopy&lt;/code&gt; would have caused Python to make new instances of those objects too.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we had an object with more layers of pointer nesting, such as a list containing a list containing a list, then &lt;code&gt;deepcopy&lt;/code&gt; would make an entirely new copy of that entire object and all its contents, all the way down, with no pointer aliasing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Immutable Objects (or: Tuples Behaving Badly)
&lt;/h2&gt;

&lt;p&gt;So far, we've been looking at lists, which are mutable objects. What happens if we look at something immutable, like a tuple?&lt;/p&gt;

&lt;p&gt;If we say that a tuple &lt;code&gt;a&lt;/code&gt; is &lt;strong&gt;immutable&lt;/strong&gt;, what we mean by that is that when &lt;code&gt;a&lt;/code&gt; is created, all its elements - &lt;code&gt;a[0]&lt;/code&gt;, &lt;code&gt;a[1]&lt;/code&gt;, and so on - are fixed. If its elements are immutable, like strings or integers, it's fairly simple to understand what this means.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;beeblebrox&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;63&lt;/span&gt;
&lt;span class="nc"&gt;Traceback &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;stdin&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tuple&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;support&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;assignment&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we try to change the value of &lt;code&gt;a[0]&lt;/code&gt;, we get an error. But, what if &lt;code&gt;a[0]&lt;/code&gt; is a pointer to something mutable, like a list?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it turns out, we can mutate the elements of &lt;code&gt;a&lt;/code&gt; in-place with no problem! This is because we're not changing the value of &lt;code&gt;a[0]&lt;/code&gt; &lt;em&gt;itself&lt;/em&gt; - it's just a pointer. What we're changing is the value of the object that &lt;code&gt;a[0]&lt;/code&gt; &lt;em&gt;points&lt;/em&gt; to. If we gave &lt;code&gt;a[0]&lt;/code&gt; its own name - a pointer alias - this would become a bit clearer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the &lt;code&gt;append&lt;/code&gt; method isn't the only way to add to a list! &lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;+=&lt;/code&gt; operator
&lt;/h3&gt;

&lt;p&gt;We can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're using the &lt;code&gt;+=&lt;/code&gt; operator, which does the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, it creates the desired object. For mutable objects, like a list, it does this by mutating the object in-place. For immutable objects, like strings, it creates an entirely new object. This is the '&lt;code&gt;+&lt;/code&gt;' part of the operation.&lt;/li&gt;
&lt;li&gt;Secondly, it reassigns the pointer it was given (in the above example, &lt;code&gt;my_list&lt;/code&gt;) to point at the desired object.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If &lt;code&gt;+=&lt;/code&gt; is called on a mutable object, then Step 2 is pretty redundant - after all, the pointer is already pointing at the desired object. But when it's called on something immutable - like a string - it &lt;em&gt;does&lt;/em&gt; need to change where the pointer points. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_string&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, World!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_string&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Hello, World!&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Strings &lt;em&gt;aren't&lt;/em&gt; mutable, so in Step 1, &lt;code&gt;+=&lt;/code&gt; creates an entirely new string &lt;code&gt;'Hello, World!'&lt;/code&gt; and changes the &lt;code&gt;my_string&lt;/code&gt; pointer to point at it.&lt;/p&gt;

&lt;p&gt;Here's a visual representation:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fplus-equals-with-strings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Farticles%2Fimg%2Fpointers-in-my-python%2Fplus-equals-with-strings.png" alt="A diagram showing the effect of using the  raw `+=` endraw  operator on string variables."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what if we try the &lt;code&gt;+=&lt;/code&gt; operator with the first element of our tuple &lt;code&gt;a&lt;/code&gt;? Spoiler alert: something silly is about to happen!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;Traceback &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;stdin&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nb"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tuple&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;support&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;assignment&lt;/span&gt;

&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What on earth is going on there? We get an error when we try to use the &lt;code&gt;+=&lt;/code&gt; with a tuple element, but the operation seems to have gone through anyway; the value of &lt;code&gt;a[0]&lt;/code&gt; has changed, at least.&lt;/p&gt;

&lt;p&gt;Step 2 is where we fall over: in this case, we can't assign directly to &lt;code&gt;a[0]&lt;/code&gt;, since it's an element of a tuple. In the &lt;code&gt;my_list&lt;/code&gt; example, however, there was no problem at all, since we can set &lt;code&gt;my_list&lt;/code&gt; to point at whatever we like.&lt;/p&gt;

&lt;p&gt;But, in step 1, the list object that &lt;code&gt;a[0]&lt;/code&gt; points at was mutated in-place, which is the change we wanted to happen. Then, in Step 2, &lt;code&gt;+=&lt;/code&gt; assigns to the pointer it's called on - &lt;code&gt;a[0]&lt;/code&gt; - and we can't assign to that! So, we get both the change and the error.&lt;/p&gt;




&lt;p&gt;So, what have we learned? We've covered namespaces, what pointers are, and where you'll see them in code, along with some examples of how immutability and pointers can interact in confusing ways. But we're only scratching the surface - stay tuned for Part 2, where we'll learn about Object IDs and why they matter, how Python knows when two objects are &lt;em&gt;really&lt;/em&gt; the same, and the difference between &lt;code&gt;is&lt;/code&gt; and &lt;code&gt;==&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build" rel="noopener noreferrer"&gt;Try Anvil - it's free, forever.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>memory</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>OAuth and OIDC: What You Need To Know</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Fri, 08 Apr 2022 14:11:35 +0000</pubDate>
      <link>https://dev.to/anvil/oauth-and-oidc-what-you-need-to-know-3ogn</link>
      <guid>https://dev.to/anvil/oauth-and-oidc-what-you-need-to-know-3ogn</guid>
      <description>&lt;h2&gt;
  
  
  OIDC under the microscope
&lt;/h2&gt;

&lt;p&gt;In a &lt;a href="https://anvil.works/blog/sso-what-is-it"&gt;previous blog post&lt;/a&gt; we covered SSO, what it is, and the two main technologies that are used to implement it. In &lt;a href="https://anvil.works/blog/saml-not-actually-that-scary"&gt;the next post&lt;/a&gt;, we covered SAML, the first of these technologies. This time, we’re taking a deep technical dive into the other: OpenID Connect - often abbreviated to OIDC - and OAuth, the authorization protocols that support it.&lt;/p&gt;

&lt;p&gt;This blog post covers the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/blog/oauth-and-oidc#what-is-oauth"&gt;What OAuth is&lt;/a&gt;, and what problems it was built to solve&lt;/li&gt;
&lt;li&gt;Why it &lt;a href="https://anvil.works/blog/oauth-and-oidc#why-do-we-need-something-else-for-authentication"&gt;can't be used for authentication&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://anvil.works/blog/oauth-and-oidc#what-is-openid-connect"&gt;What OpenID Connect is&lt;/a&gt;, and how it uses OAuth&lt;/li&gt;
&lt;li&gt;Importantly, &lt;a href="https://anvil.works/blog/oauth-and-oidc#oidc-and-security"&gt;is it secure&lt;/a&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's jump in!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OAuth?
&lt;/h2&gt;

&lt;p&gt;This section gives a fairly high-level primer on OAuth, intended to illustrate what it is &lt;em&gt;in the context of OIDC&lt;/em&gt;. In and of itself, OAuth is a deep topic with lots of interesting security aspects; for the sake of brevity, we won't be covering all of them.&lt;/p&gt;

&lt;p&gt;Wikipedia defines OAuth (short for &lt;strong&gt;O&lt;/strong&gt;pen &lt;strong&gt;Auth&lt;/strong&gt;orization) as 'an open standard for access delegation'. In this context, 'access delegation' means allowing one entity &lt;em&gt;access&lt;/em&gt; to something (for example, information) controlled by another entity. The act of allowing this access is &lt;em&gt;delegation&lt;/em&gt;, hence 'access delegation'.&lt;/p&gt;

&lt;h3&gt;
  
  
  ... so what does it &lt;em&gt;do&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;Let's take a real-world example: I have a GMail account, and I want to use a service that'll go through all the automated emails I received in the last 90 days and send responses asking each of the senders to delete the data they have on file about me. That means that the service will need to be able to read my emails, and send emails from my account. However, I don't want to just &lt;em&gt;give&lt;/em&gt; the service the credentials I use to log in to my Google account; that would also give it access to my Drive, any location data history the Google Maps has collected, and so on. &lt;/p&gt;

&lt;p&gt;Instead, the service should only be able to perform the actions I want it to, and that's where OAuth comes in. OAuth provides a mechanism for allowing that service to request access specifically to only the actions it needs, without compromising the security of other information or restricted actions managed by my Google account.&lt;/p&gt;

&lt;p&gt;In OAuth world, there are a few different entities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;user&lt;/strong&gt; is called the &lt;strong&gt;Resource Owner&lt;/strong&gt;: in the above example, this is me! I &lt;em&gt;own&lt;/em&gt; the resources (the ability to read and send email) that I want to be able to share with the client service.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;client service&lt;/strong&gt; is called the &lt;strong&gt;Relying Party&lt;/strong&gt;: in the above example, this is the service that'll automatically read and send emails for me, and it &lt;em&gt;relies&lt;/em&gt; on an OAuth flow in order to get access to those actions.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Identity Provider&lt;/strong&gt; is also called the &lt;strong&gt;Authorisation Server&lt;/strong&gt;: This is where I can go to prove ownership of my Google account, and &lt;em&gt;authorise&lt;/em&gt; the client to use my resources.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Resource Server&lt;/strong&gt; is where those resources to which I have delegated access live. In the above example, this is a GMail server. In a lot of examples, this will be managed by the same organisation as the Authorisation Sever, but that isn't strictly necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;The big concept that drives OAuth is the idea of &lt;strong&gt;tokens&lt;/strong&gt;. Tokens are objects that the Authorisation Server can issue for a client to use, and in OAuth there are two different kinds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access Tokens&lt;/strong&gt; are used by the client to access a given resources from the Resource Server. The Resources Server needs to be able to parse the information from within the token, and give exactly the access requested (and no more!). Access Tokens are also sometimes called &lt;strong&gt;bearer tokens&lt;/strong&gt;, because any entity which gets hold of them ('bears' them) will then have access to those resources. For this reason, they should have an expiration date built-in, after which point the Resource Server will deny access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refresh Tokens&lt;/strong&gt; are used by the client to get a new Access Token if the one they currently have has expired. These tokens are longer-lived, and are typically stored by the client application in a secure server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a few different important qualities that tokens need to have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They should be opaque to the client application. The email service in the above example doesn't need to know what's inside the tokens it receives; all it needs to do is send them on to the relevant servers.&lt;/li&gt;
&lt;li&gt;When the Relying Party makes a request for a token, that request will include a &lt;strong&gt;scope&lt;/strong&gt; (or multiple scopes) for the token that determines exactly what resources it grants access to. OAuth is a standard and not a framework, so it doesn't set out any scopes explicitly, instead leaving them up to the internal implementation of the Authorisation and Resource Servers. In the email service scenario, the scopes involved would require allowing access to reading and sending emails, but not (for example) access to my Google Drive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An OAuth Authorisation Server will have a few different endpoints which are used at various stages in the process. In the following flow, we'll see a couple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/authorize&lt;/code&gt;, which lets the user grant access - for example, &lt;code&gt;https://my-oauth-server.com/authorize&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/token&lt;/code&gt;, which is where the Relying Party sends its requests for tokens - for example, &lt;code&gt;https://my-oauth-server.com/token&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Resource Server will also have a variety of endpoints, depending on what kind of resources it serves; it's up to the Relying Party to make sure they access the correct one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nhOAeebh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/oauth-and-oidc/oauth-flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nhOAeebh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/oauth-and-oidc/oauth-flow.png" alt="A diagram illustrating the OAuth flow described immediately below." width="880" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, authorising a client to use some of your resources that are hosted on a Resource Server goes like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You, the Resource Owner, visit the Relying Party that wants access to your resources.

&lt;ul&gt;
&lt;li&gt;In the above example, this would be visiting the website of the service that'll automatically ask people to delete my data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Relying Party sends you to the Authorisation Server's &lt;code&gt;/authorize&lt;/code&gt; endpoint with a request for an authorisation code.

&lt;ul&gt;
&lt;li&gt;This is where you'll be redirected in your browser to a Google screen, asking you if you want to allow the email service appropriate access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You authenticate with the Authorisation Server and grant resource access. Your role as the Resource Owner is now done.&lt;/li&gt;
&lt;li&gt;The Authorisation Server sends you back to the Relying Party along with an authorisation code.

&lt;ul&gt;
&lt;li&gt;In the above example, this is you being redirected back to the website for the email service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Relying Party then uses that code to request an Access Token with appropriate scopes from the Authorisation Server's &lt;code&gt;/token&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;The Authorisation Server then mints a new Access Token and (optionally) a Refresh Token.&lt;/li&gt;
&lt;li&gt;The Authorisation Server sends those tokens back to the Relying Party.&lt;/li&gt;
&lt;li&gt;The Relying Party sends the Access Token to a relevant endpoint at the Resource Server in order to ask for access.

&lt;ul&gt;
&lt;li&gt;This endpoint is where the email service asks to download the last 90 days' worth of emails to my inbox.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The Resource Server validates the token and grants access.

&lt;ul&gt;
&lt;li&gt;This is the point at which access to my emails has now been successfully delegated to the automatic email service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, going forwards, as long as the client application has a valid Access Token (either from this process or by requesting a new one using its Refresh Token), it doesn't need you as the Resource Owner to grant access again. If the Refresh Token expires or is revoked, then this flow will need to happen again.&lt;/p&gt;

&lt;p&gt;And that's how OAuth allows you to delegate access to your resources!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we need something else for authentication?
&lt;/h2&gt;

&lt;p&gt;Reading the above, you might think that OAuth is sufficient for &lt;em&gt;authentication&lt;/em&gt; purposes. After all, if you want to use an OAuth-provided identity to log in with a third party service, OAuth already exists to facilitate permissions sharing between those two services, right? Well, that's just the thing: an OAuth token creates a relationship between those two services, letting one use the other's resources. You, as the user, are really only there at token creation time in order to agree that that relationship is OK; after that, OAuth doesn't care whether or not you're authenticated.&lt;/p&gt;

&lt;p&gt;OAuth isn't about identity, it's about resources, and the &lt;em&gt;authorisation&lt;/em&gt; to use those resources. These concepts are closely connected, but they're not the same, and getting them mixed up can lead to gaps in security. It's absolutely possible to do authentication with OAuth, and it's people did before OIDC - but you have to be very careful when implementing it.&lt;/p&gt;

&lt;p&gt;For example, it might be tempting to assume that a valid Access Token constitutes proof of identity. After all, the user had to authenticate with the OAuth identity provider in order for that Access Token to exist. Unfortunately, there are &lt;a href="https://oauth.net/articles/authentication/"&gt;multiple issues with this approach&lt;/a&gt;. One problem is that user authentication isn't the only time that Access Tokens can be created; any client with a Refresh Token can create one. This is in fact a fundamental design requirement of OAuth, since it exists to ease the sharing of resources between services, and &lt;em&gt;shouldn't&lt;/em&gt; require user presence at all stages!&lt;/p&gt;

&lt;p&gt;Another issue is that, since Access Tokens are opaque to the client by design, the third-party service that receives the Access Token as proof of identity won't be able to get any information from it. In fact, the service won't even be able to inspect the token to verify that the user is who they say they are! This is because the client isn't actually who the Access Token is &lt;em&gt;for&lt;/em&gt; - it's meant to be parsed by the OAuth Resource Server, not the third-party service itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  OAuth isn't &lt;em&gt;unusable&lt;/em&gt; for authentication - but we can do better
&lt;/h3&gt;

&lt;p&gt;In the past, we worked around all this by having the client follow the above OAuth Flow, after which it would use the resulting Access Token to hit an endpoint on the Authorisation Server. This endpoint, often located at &lt;code&gt;/me&lt;/code&gt;, would then allow the Authorisation Server to parse that Access Token and tell the Relying Party on which user's behalf it was issued. But, this is fairly roundabout, and easy to get wrong; for example, when building a Relying Party you'd need to make sure that you only used Access Tokens received directly from the Authorisation Server in order to mitigate the risk of a malicious actor using an ill-gotten token to falsely authenticate.&lt;/p&gt;

&lt;p&gt;What if we had something designed for the purpose? We'd need a token that's only created at authentication time, and &lt;em&gt;is&lt;/em&gt; designed to be parsed by the client.&lt;/p&gt;

&lt;p&gt;That's what OpenID Connect does!&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OpenID Connect?
&lt;/h2&gt;

&lt;p&gt;The key thing that OIDC provides is the idea of an ID Token - a token designed to be used as proof of OAuth identity, for consumption by the client service. ID Tokens, unlike Access and Refresh tokens, have a specified format: they're constructed as JSON Web Tokens (or JWTs). JWTs are JSON payloads which are then cryptographically signed by the issuer. This means that they're protected from tampering, but they can still be parsed by the recipient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3yLWSW5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/oauth-and-oidc/oidc-flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3yLWSW5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/oauth-and-oidc/oidc-flow.png" alt="A diagram illustrating the OIDC flow described immediately below." width="880" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The flow for a user authenticating with a Relying Party using their OAuth Identity then looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You, the Resource Owner, visit the Relying Party with which you want to authenticate.&lt;/li&gt;
&lt;li&gt;The Relying Party sends you to the Authorisation Server's &lt;code&gt;/authorize&lt;/code&gt; endpoint, along with a request for one or more tokens.

&lt;ul&gt;
&lt;li&gt;At this point, the Relying Party can request either an ID Token on its own, or an ID Token &lt;em&gt;and&lt;/em&gt; an Access Token.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You authenticate yourself with the Authorisation Server.&lt;/li&gt;
&lt;li&gt;The Authorisation Server then mints the tokens that the Relying Party requested, and sends them back to the Relying Party.&lt;/li&gt;
&lt;li&gt;The Relying Party can now decrypt the ID Token, and use it to verify your identity and authenticate you.

&lt;ul&gt;
&lt;li&gt;If the Relying Party also requested an Access Token, it can then use this later to get more user information about you from the Authorisation Server by using it to hit a &lt;code&gt;/userinfo&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note that the Resource Server isn't involved at all. The only 'resource' you're trying to share is proof of your identity, and that's solely the domain of the Authorisation Server.&lt;/p&gt;

&lt;p&gt;In reality, the ID Token is quite different to the Access and Refresh Token types. It isn't meant to be used by the Resource or Authorisation Servers; it's just a record of the authentication event that occurred when the user logged in to the Authorisation Server. But that's all that the Relying Party &lt;em&gt;needs&lt;/em&gt; in order to know who you are.&lt;/p&gt;

&lt;p&gt;If the Relying Party also wants to know extra information about you, then it needs to request an Access Token which has the relevant scopes - for example, &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;address&lt;/code&gt; - and it can do this at the same time, as mentioned in the flow above. (It might seem like one could just use the &lt;code&gt;/userinfo&lt;/code&gt; endpoint to use OAuth itself for authentication, but that endpoint is in fact something that's defined by the OIDC spec, and isn't required for OAuth.)&lt;/p&gt;

&lt;h2&gt;
  
  
  OIDC and security
&lt;/h2&gt;

&lt;p&gt;So, how can this all go wrong? Well, there are a few different ways, including the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The OAuth Authorisation Server wrongly grants tokens to a malicious third party.&lt;/li&gt;
&lt;li&gt;An Access Token created for a legitimate Relying Party makes its way into the possession of a malicious entity, enabling it to masquerade as that Relying Party.&lt;/li&gt;
&lt;li&gt;The Relying Party receives and trusts a token that was actually created by a malicious entity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to address the first problem, a Relying Party needs to have an existing relationship with the OAuth Identity Provider before it can use OIDC to authenticate its users. This involves the Relying Party being registered with that OAuth Server and having a &lt;strong&gt;client ID&lt;/strong&gt; and a &lt;strong&gt;client secret&lt;/strong&gt;. That identifying information is then included whenever the Relying Party makes a request for tokens, so that the OAuth Server can be sure that the request is legitimate. Of course, this means that that ID and secret need to be stored securely by the Relying Party; for instance, all API calls using them should be made from a server, rather than a user's browser.&lt;/p&gt;

&lt;p&gt;The second possibility could come about in a couple of ways; either the Access Token is intercepted in transit, or it's leaked to external parties by the legitimate Relying Party. To avoid the first of these, all the API calls should be made using HTTPS, so that all the traffic is encrypted and can't be inspected by any onlookers. To avoid the second problem, it's important that the Relying Party should always treat Access Tokens securely, and this includes only ever using them in a server and not in the user's browser (just as with the client ID and secret).&lt;/p&gt;

&lt;p&gt;The third problem is largely prevented by the fact that ID Tokens are JWTs, which are cryptographically signed by design. If, however, the OAuth Authorisation Server isn't signing its JWTs (which it should!), then this vulnerability can be mitigated by the Relying Party only ever trusting tokens that result from a direct API call. It can also verify the tokens it receives by sending them to the Authorisation Server's &lt;code&gt;/introspect&lt;/code&gt; endpoint, which will tell the Relying Party whether or not a given token is valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using OpenID Connect in your web apps
&lt;/h2&gt;

&lt;p&gt;So, what do you need to do in order to enable OpenID Connect authentication for your web apps? Well, you need your web app to be able to make the appropriate API calls to your OAuth Identity Provider of choice (making sure you ask for the right kind of tokens!) and for your app to be able to safely handle the responses it gets. Unfortunately, this can be pretty fraught, because you need to be certain that you're doing everything correctly at every stage of the process, or else you risk falling foul of some of the vulnerabilities we discussed above. However, once it's set up, you get all the &lt;a href="https://anvil.works/blog/sso-what-is-it#what-are-the-benefits"&gt;benefits of SSO&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anvil apps come with several ready-made options for using OIDC-based SSO; several OpenID Identity Providers such as &lt;a href="https://anvil.works/beta-docs/integrations/google/authenticating-users"&gt;Google&lt;/a&gt; and &lt;a href="https://anvil.works/beta-docs/integrations/facebook/linking-facebook-and-anvil"&gt;Facebook&lt;/a&gt; are already configured.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N6xtdLkB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/oauth-and-oidc/anvil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N6xtdLkB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/oauth-and-oidc/anvil.png" alt="The Users Service configuration page, with the options to allow login with Google and Fcebook highlighted." width="880" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's nice to know about tokens... but you don't have to.&lt;/p&gt;

&lt;p&gt;Enabling SSO for your users is as simple as using Anvil's built-in User Authentication service, and ticking a single checkbox. Easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works/"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build"&gt;Try Anvil for free!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>authentication</category>
      <category>oidc</category>
    </item>
    <item>
      <title>Creating a Pure Python Web Dashboard with the QuickBooks API</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Fri, 25 Mar 2022 15:20:25 +0000</pubDate>
      <link>https://dev.to/anvil/creating-a-pure-python-web-dashboard-with-the-quickbooks-api-1g0a</link>
      <guid>https://dev.to/anvil/creating-a-pure-python-web-dashboard-with-the-quickbooks-api-1g0a</guid>
      <description>&lt;p&gt;&lt;a href="https://quickbooks.intuit.com/"&gt;QuickBooks&lt;/a&gt; is flexible, powerful accounting software, used by businesses and individuals alike. It also has a &lt;a href="https://developer.intuit.com/app/developer/qbo/docs/develop"&gt;robust API&lt;/a&gt; - and I'm going to show you how to use it. We're going to build a public dashboard, displaying company revenue by month.&lt;/p&gt;

&lt;p&gt;We're building it with &lt;a href="https://anvil.works/"&gt;Anvil&lt;/a&gt;, so we can build and deploy this app entirely in Python (no HTML or JavaScript required!). We're not just driving the QuickBooks API with Python code -- we're building the front-end, including interactive plots in the browser, with Python too!&lt;/p&gt;

&lt;p&gt;Here's the finished app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--faVXrRWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/finished-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--faVXrRWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/finished-app.png" alt="The app we're going to build." width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quickbooks-revenue-viewer.anvil.app"&gt;Open the app here&lt;/a&gt;, or read on for a run-down of how it's built!&lt;/p&gt;

&lt;p&gt;Here's how we put this dashboard together:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create our apps and set up credentials&lt;/li&gt;
&lt;li&gt;Authenticating and getting API tokens&lt;/li&gt;
&lt;li&gt;Calling the QuickBooks API to get our data&lt;/li&gt;
&lt;li&gt;Display our data to our users&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can open the app's source code and follow along -- just click below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:DT32LOG3M6456ZZV=OXVM6GNKPEYIXP3R5PFVGUCH"&gt;Clone the app!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ready? Let's begin.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Setting up our apps and credentials
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nec85t1_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/docs/img/create-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nec85t1_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/docs/img/create-app.png" alt="Creating an Anvil app is fast and easy." width="880" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get started, we just head to the &lt;a href="https://anvil.works/build"&gt;Anvil App Editor&lt;/a&gt;, hit 'New Blank App' and choose 'Material Design'. This gives us a layout where we can start dragging and dropping components, such as a title.&lt;/p&gt;

&lt;p&gt;Then, deploying the app is as simple as clicking 'Publish App' in the app's settings, choosing a URL, and hitting 'Apply'.&lt;/p&gt;

&lt;p&gt;Now our app is available to anyone on the web - but it's not very exciting yet! To start pulling accounting data from Quickbooks, we'll need to set up an account there too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L_o1bE48--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/create-intuit-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L_o1bE48--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/create-intuit-app.png" alt="Creating an Intuit app to provide data to our Anvil app." width="610" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We head to the &lt;a href="https://developer.intuit.com/app/developer/homepage"&gt;Intuit developer page&lt;/a&gt; and sign up there for a developer account. From there, we can create a &lt;a href="https://developer.intuit.com/app/developer/qbo/docs/develop/sandboxes"&gt;sandbox company&lt;/a&gt;, which is a dummy company that comes pre-filled with some example accounting data.&lt;/p&gt;

&lt;p&gt;Once we've got our sandbox company all set up, we go to the &lt;a href="https://developer.intuit.com/app/developer/dashboard"&gt;Dashboard&lt;/a&gt; to create an Intuit app. This is the entity that provides us with authentication details, so that our Anvil app can access our QuickBooks data.&lt;/p&gt;

&lt;p&gt;Then, from the Dashboard, we can access the credentials from our Intuit app; we're looking for a &lt;code&gt;Client ID&lt;/code&gt; and &lt;code&gt;Client Secret&lt;/code&gt;, and they can be found under the 'Keys and OAuth' section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MYiNlmia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/client-id-and-secret.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MYiNlmia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/client-id-and-secret.png" alt="An example of the credentials we need." width="880" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We store these in our Anvil app as &lt;a href="https://anvil.works/docs/security/encrypting-secret-data"&gt;App Secrets&lt;/a&gt;, so we can access them later from code.&lt;/p&gt;

&lt;p&gt;Now we're armed with the credentials we need, we can get started on the authentication flow for our Anvil app!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Getting API tokens
&lt;/h2&gt;

&lt;p&gt;To access the QuickBooks API, our app needs API tokens. We have to get those interactively (via OAuth), but they're then valid for 100 days, so we can store them in our database and use them to fetch data whenever our app is opened. (We're not going to get into a full OAuth tutorial here -- you can see how it works in our app's source code, or read a &lt;a href="https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0"&gt;more detailed guide&lt;/a&gt; in the QuickBooks docs).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N8N8EwHY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/first-authentication.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N8N8EwHY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/first-authentication.gif" alt="Authenticating our app for the first time with OAuth." width="880" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have tokens, we store them in our app's &lt;a href="https://anvil.works/docs/data-tables"&gt;built-in database&lt;/a&gt;, using Anvil's &lt;a href="https://anvil.works/docs/security/encrypting-secret-data"&gt;built-in encryption&lt;/a&gt;. When the token expires, we'll need to repeat the OAuth login process, but that's pretty quick:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y5jArbCW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/authenticating.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y5jArbCW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/authenticating.gif" alt="Reauthenticating - once we've already connected our two apps - is really fast!" width="880" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Call the QuickBooks API
&lt;/h2&gt;

&lt;p&gt;Now our app has all the credentials it needs to start making calls to the QuickBooks API. We're going to use the &lt;a href="https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/profitandloss"&gt;ProfitAndLoss&lt;/a&gt; endpoint to retrieve data about our total income over the last year, grouped by month.&lt;/p&gt;

&lt;p&gt;Here's the server function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@anvil.server.callable
def get_past_yearly_data():
  # The 'quickbooks_auth' table has one row, with all our tokens in. Fetch it:
  row = app_tables.quickbooks_auth.get()

  # Decrypt the Access Token
  access_token = anvil.secrets.decrypt_with_key('tokens_key', row['encrypted_access_token'])

  # Hit the ProfitAndLoss endpoint
  today = date.today()
  resp = requests.get(
    url=f'https://sandbox-quickbooks.api.intuit.com/v3/company/{row['realm_id']}/reports/ProfitAndLoss',
    headers={
      "accept": "application/json",
      "authorization": f"Bearer {access_token}",
      "content-type": "application/json",
    },
    params={
      'start_date': f'{today.year - 1}-{today.month + 1}-01',
      'end_date': today.isoformat(),
      'summarize_column_by': 'Month',
      'minorversion': "57"
    }
  ).json()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we see the code for the API call; we get the access token from our Data Table and decrypt it, then make a &lt;code&gt;GET&lt;/code&gt; request using the Python &lt;a href="https://pypi.org/project/requests/"&gt;requests&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;The data that comes back is a little gnarly (&lt;a href="https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/profitandloss"&gt;here's a sample&lt;/a&gt;), but it's nothing we can't fix with a few list comprehensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  months = [col["ColTitle"] for col in resp["Columns"]["Column"]][1:]
  summary = [col["Summary"] for col in resp["Rows"]["Row"] if col["Summary"]["ColData"][0]["value"] == "Total Income"][0]["ColData"][1:]
  incomes = [item["value"] for item in summary]

  return months, incomes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Display our data
&lt;/h2&gt;

&lt;p&gt;Now for the easiest part: Call that &lt;code&gt;get_past_yearly_data()&lt;/code&gt; function from the browser, and put the results into a &lt;a href="https://anvil.works/docs/client/components/plots"&gt;Plotly chart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We create a Plot component using Anvil's &lt;a href="https://anvil.works/articles/python-gui-builder-web"&gt;drag-and-drop GUI editor&lt;/a&gt;, and call it &lt;code&gt;revenue_plot&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NaLNQg8z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/add-plot-component.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NaLNQg8z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/add-plot-component.gif" alt="Creating a Plot component with the Anvil editor" width="880" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anvil lets us &lt;a href="https://anvil.works/docs/server"&gt;call server functions&lt;/a&gt; directly from browser code. Our server function returns two lists: one with all the months for which we have data, and one with the incomes for those months.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # This code runs in the browser:
  months, incomes = anvil.server.call('get_past_yearly_data')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can import the Plotly API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import plotly.graph_objects as go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and make a bar chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.revenue_plot.data = go.Bar(
    x = months,
    y = incomes,
    marker={'color': '#39bfbc'}
)

self.revenue_plot.layout = go.Layout(
    title=go.layout.Title(text="Last year's monthly income", x=0.5),
    yaxis_title="Income (USD)"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! Here's our finished app:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--faVXrRWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/finished-app.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--faVXrRWW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/articles/img/quickbooks-revenue-viewer/finished-app.png" alt="Our app, showing the data we got from our API call represented in a Plotly plot." width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  See the code
&lt;/h2&gt;

&lt;p&gt;If you want to see the source code for this app, you can click &lt;a href="https://anvil.works/build#clone:DT32LOG3M6456ZZV=OXVM6GNKPEYIXP3R5PFVGUCH"&gt;here&lt;/a&gt; to clone it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Go even further
&lt;/h2&gt;

&lt;p&gt;Of course, we've only barely scratched the surface of what it's possible to do with the QuickBooks API. Using this framework, you could build a fully featured dashboard and make much more use of Plotly's interactive features. Have a go at extending what we've built today!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build#clone:DT32LOG3M6456ZZV=OXVM6GNKPEYIXP3R5PFVGUCH"&gt;Clone the app!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://dev.to/"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build"&gt;Try Anvil for free!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>quickbooks</category>
      <category>python</category>
      <category>webdev</category>
      <category>dashboard</category>
    </item>
    <item>
      <title>A Gentle Introduction to SAML Authentication</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Thu, 03 Mar 2022 15:29:32 +0000</pubDate>
      <link>https://dev.to/anvil/a-gentle-introduction-to-saml-authentication-11eh</link>
      <guid>https://dev.to/anvil/a-gentle-introduction-to-saml-authentication-11eh</guid>
      <description>&lt;h2&gt;
  
  
  Implementing SSO with the power of XML
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://anvil.works/blog/sso-what-is-it" rel="noopener noreferrer"&gt;previous post in this series&lt;/a&gt; we covered Single Sign-On, what it is, and what it means for web services. This time, we’re taking a deep technical dive into one of the two main technologies that are used to implement it: Security Assertion Markup Language, colloquially known as SAML. So what is it, and how can we use it for SSO?&lt;/p&gt;

&lt;p&gt;SAML defines an interoperable, standardised protocol for letting a web service (in SAML world, a Service Provider or SP) authenticate a user with an identity provided by an external party (an Identity Provider or IdP). In essence, SSO with SAML allows a Service Provider to delegate its user authentication responsibilities to an Identity Provider. All the communications between the SP and the IdP follow a particular XML format, and SAML protocols can also handle use cases for authorization and identity provider discovery - but, in this blog post, we'll be focusing specifically on the web SSO use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  SAML from beginning to end
&lt;/h2&gt;

&lt;p&gt;Let's say you're a web developer who wants to be able to use SAML SSO to authenticate your users. What exactly do you have to know?&lt;/p&gt;

&lt;p&gt;A typical SAML 2.0 SSO authentication flow goes like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user visits the Service Provider with their browser.&lt;/li&gt;
&lt;li&gt;The Service Provider redirects the user to the Identity Provider, along with a SAML &lt;strong&gt;Authentication Request&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The user authenticates with the Identity Provider, if they aren't already authenticated.&lt;/li&gt;
&lt;li&gt;The Identity Provider returns the user to the Service Provider, along with a SAML &lt;strong&gt;Authentication Assertion&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The Service Provider cryptographically verifies that authentication assertion.&lt;/li&gt;
&lt;li&gt;The user is now authenticated with the Service Provider.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AcxwGgPHZUA3uWAK67s-onA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F1400%2F1%2AcxwGgPHZUA3uWAK67s-onA.png" alt="Instead of authenticating the user directly, the Service Provider sends them off to the Identity Provider to handle it."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a couple of different ways some of these steps can happen, but the broad strokes stay the same. One interesting property of this flow is that the SP and IdP never actually communicate directly. They redirect the user's browser back and forth along with SAML Requests and Assertions, but they don't actually need to be on the same network, which means you can use an IdP that's on a private corporate network to authenticate with an SP that's on the public internet.&lt;/p&gt;

&lt;p&gt;Before the above flow can happen, both the SP and the IdP need to be configured to trust each other, which is done by exchanging some key information between them. In order to get everything set up, you'll need to understand a bit more about what exactly those entities &lt;em&gt;are&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What &lt;em&gt;is&lt;/em&gt; a Service Provider?
&lt;/h3&gt;

&lt;p&gt;If you want to use SAML SSO to let users authenticate wtih your web service, you'll have to set that web service up to act as a Service Provider for SAML purposes. Perhaps you're using a development platform with a SAML integration (like &lt;a href="https://anvil.works/docs/integrations/saml" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt;!), in which case this is simple - but, if you're doing it from scratch, here's what you need to know.&lt;/p&gt;

&lt;p&gt;The key features of a Service Provider which allow it to interact with an Identity Provider are these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has a unique identifier which allows Identity Providers to keep track of it&lt;/li&gt;
&lt;li&gt;It owns a signing certificate, which allows Identity Providers to trust the messages it sends&lt;/li&gt;
&lt;li&gt;It has a specific HTTP endpoint, which allows Identity Providers to know where to send any replies (including Authentication Assertions)&lt;/li&gt;
&lt;li&gt;It needs to be able to send users to an Identity Provider in order to authenticate, and to be able to understand whatever response the Identity Provider returns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at the three first bullet points. When configuring a relationship between your SP and IdP, all those pieces of information about your Service Provider need to be given to the Identity Provider you'd like to use. Lots of IdPs provide a neat way to do this: they expect a metadata file produced by your SP, which bundles all this information up. If you're building a Service Provider, you might like to add functionality to construct and download a file in the expected format.&lt;/p&gt;

&lt;p&gt;Below is an example Service Provider metadata file (downloaded from an Anvil app), which illustrates how each of those 3 pieces of information fit into it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?xml version="1.0"?&amp;gt;
  &amp;lt;md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" validUntil="2020-10-23T14:15:21Z" cacheDuration="PT604800S" entityID="http://anvil.works/apps/_/saml-app/79aac3df685d66" ID="ANVIL_444fcc73"&amp;gt;
    &amp;lt;md:SPSSODescriptor AuthnRequestsSigned="true" WantAssertionsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"&amp;gt;
      &amp;lt;md:KeyDescriptor use="signing"&amp;gt;
        &amp;lt;ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&amp;gt;
          &amp;lt;ds:X509Data&amp;gt;
            &amp;lt;ds:X509Certificate&amp;gt;
              -----BEGIN CERTIFICATE-----
              MIIE...
            &amp;lt;/ds:X509Certificate&amp;gt; 
          &amp;lt;/ds:X509Data&amp;gt;
        &amp;lt;/ds:KeyInfo&amp;gt;
      &amp;lt;/md:KeyDescriptor&amp;gt;
      &amp;lt;md:NameIDFormat&amp;gt;
        urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
      &amp;lt;/md:NameIDFormat&amp;gt;
      &amp;lt;md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://anvil.works/apps/_/saml_auth_login" index="1"/&amp;gt;
    &amp;lt;/md:SPSSODescriptor&amp;gt;
  &amp;lt;/md:EntityDescriptor&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firstly, within the &lt;code&gt;md:EntityDescriptor&lt;/code&gt; tag, there's an attribute called &lt;code&gt;entityID&lt;/code&gt;, the value of which is the unique identifier for your Service Provider. Then, further down, we can see a &lt;code&gt;ds:X509Data&lt;/code&gt; section, which is where your Service Provider's signing certificate would be placed. (In the above example, the certificate itself is truncated for brevity).&lt;/p&gt;

&lt;p&gt;Finally, within the &lt;code&gt;md:AssertionConsumerService&lt;/code&gt; tag, we can see a &lt;code&gt;Location&lt;/code&gt; attribute, containing a URL. This is the endpoint to which the Service Provider expects any responses to be sent. Within that tag is also a &lt;code&gt;Binding&lt;/code&gt; attribute, which tells the Identity Provider that (in this case) the SP expects any responses to that endpoint to be sent via an &lt;code&gt;HTTP-POST&lt;/code&gt; request.&lt;/p&gt;

&lt;p&gt;Even if an Identity Provider doesn't have an option to upload a metadata file from your Service Provider, it will definitely need to ask you for these three pieces of data in some other way. Without them, it won't know what your service is, why it should trust it, or how to talk to it.&lt;/p&gt;

&lt;p&gt;So, once you've defined those three aspects of your Service Provider, you'll need to address the last bullet point on the list above: your SP needs to be able to actually interact with the Identity Provider. That means sending users there when they want to authenticate, and understanding what the Identity Provider tells you about them when they come back. In order to make that happen, we'll need to understand more about what an Identity Provider does.&lt;/p&gt;

&lt;h3&gt;
  
  
  What &lt;em&gt;is&lt;/em&gt; an Identity Provider?
&lt;/h3&gt;

&lt;p&gt;The things that an Identity Provider needs - perhaps unsurprisingly! - mirror those of a Service Provider. Here's what defines an IdP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has a unique identifier which allows Service Providers to keep track of it&lt;/li&gt;
&lt;li&gt;It owns a signing certificate, which allows Service Providers to trust messages it sends&lt;/li&gt;
&lt;li&gt;It has a specific HTTP endpoint, which allows Service Providers to know where to send their Authentication Requests&lt;/li&gt;
&lt;li&gt;It needs to be able to receive Authentication Requests from Service Providers, handle those requests (including authenticating users), and send a reply that the Service Provider can understand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just as with Service Providers, it's typical for the three pieces of information above (identity, certificate and endpoint) to be bundled into a metadata file. The main difference between the two types of metadata file is that rather than an &lt;code&gt;AssertionConsumerService&lt;/code&gt; URL (which is where a Service Provider consumes Authentication Assertions), an Identity Provider will have an &lt;code&gt;SingleSignOnService&lt;/code&gt; URL (where it consumes Authentication Requests for the purposes of SSO).&lt;/p&gt;

&lt;p&gt;As mentioned above, there are a couple ways configurations can differ - for example, the IdP can expect the user to be sent over with either a &lt;code&gt;HTTP-GET&lt;/code&gt; or &lt;code&gt;HTTP-POST&lt;/code&gt; request, or sometimes either - and all this information would also be expressed in the SP's metadata document.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication Requests and Assertions
&lt;/h3&gt;

&lt;p&gt;With the above information successfully exchanged, our Service Provider and our Identity Provider know who each other are, how to trust each other's messages, and where to send any messages of their own. Great! So what's actually &lt;em&gt;in&lt;/em&gt; those messages?&lt;/p&gt;

&lt;p&gt;To kick off the process of authenticating a user with SAML, a user visits the Service Provider's website or app (step 1 in the flow above). The Service Provider will then send that user to the Identity Provider along with an &lt;strong&gt;Authentication Request&lt;/strong&gt; (step 2). This Request is contained within an XML document, and that document is then sent as a query parameter on an HTTP request (made from the user's browser) to the Identity Provider's &lt;code&gt;SingleSignOnService&lt;/code&gt; URL. This Authentication Request can contain information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The identity of the Service Provider which is making the request&lt;/li&gt;
&lt;li&gt;What kind of authentication the SP wants the IdP to perform (for example, whether it should require a password from the user who's trying to authenticate)&lt;/li&gt;
&lt;li&gt;Whether the user should be allowed to create a new account when they arrive at the IdP (thus allowing a new user to authenticate with the Service Provider)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Request is contained within a larger XML document which should also include a Signature section; that sections then contains a signature over the Authentication Request, generated using the Service Provider's signing certificate. This signature allows the Identity Provider to verify that the request was sent by the Service Provider and that it hasn't been tampered with in transit. All this &lt;em&gt;would&lt;/em&gt; be pretty standard public-key cryptography procedure if the payload were a byte-string rather than XML, but - as we'll discuss later - multiple byte-strings can represent the same XML data, and this can introduce complications down the line.&lt;/p&gt;

&lt;p&gt;The Authentication Assertion that the Identity Provider sends once the user has authenticated is very similar; it's sent (also via HTTP) to the Service Provider's &lt;code&gt;AssertionConsumerService&lt;/code&gt; URL, and it can include the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The identity of the IdP&lt;/li&gt;
&lt;li&gt;The identity of the Service Provider for whom the Assertion is intended&lt;/li&gt;
&lt;li&gt;The identity of the user who has authenticated, and optionally some attributes that the IdP has stored about them (for example, name or email address)&lt;/li&gt;
&lt;li&gt;How that user authenticated (for example, as above, using a password)&lt;/li&gt;
&lt;li&gt;The conditions under which the Assertion should be considered valid (for example, only within a certain time window)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like the Request made by the Service Provider, the Assertion is contained within a larger XML document, which also contains a signature over that Assertion.&lt;/p&gt;

&lt;p&gt;When the Service Provider receives that Authentication Assertion and verifies its signature, it can be confident that the user has successfully completed the required login flow, and safely let them access login-restricted resources. You're done!&lt;/p&gt;

&lt;h2&gt;
  
  
  SAML and security
&lt;/h2&gt;

&lt;p&gt;SAML's security posture is as follows: when the SP and IdP are being configured to trust each other, part of the data exchanged between them is access to each other's &lt;code&gt;X509Certificate&lt;/code&gt; - a certificate used for public-key cryptography. Typically, whenever a SAML message (in XML format) is then sent between the two parties during an authentication flow, that XML will be signed by the sending party, using their private key. The receiving party will then be able to use the &lt;code&gt;X509Certificate&lt;/code&gt; that they have been given in order to verify that that SAML message is definitely from the sending party and that the data hasn't been modified during transit.&lt;/p&gt;

&lt;p&gt;Over the years, there have been a &lt;a href="https://workos.com/blog/fun-with-saml-sso-vulnerabilities-and-footguns" rel="noopener noreferrer"&gt;lot of vulnerabilities&lt;/a&gt; found in SAML systems, of various kinds. Most of them stem from the fact that the entire framework is based on XML, which is optimised for flexibility rather than a single robust path.&lt;/p&gt;

&lt;p&gt;Let's take a look at one particular way that that flexibility can introduce vulnerabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Signatures and Canonical forms
&lt;/h3&gt;

&lt;p&gt;As mentioned above, SAML uses what sounds like fairly standard public-key cryptography - but there's a complicating factor: signing XML data is &lt;em&gt;hard&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The fundamental problem with signing XML is that two different XML documents could represent the same information. For example, look at these two tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;saml:Issuer&amp;gt;http://sp.example.com/demo1/metadata.php&amp;lt;/saml:Issuer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;  saml:Issuer  &amp;gt;&amp;lt;http://sp.example.com/demo1/metadata.php&amp;lt;/  saml:Issuer  &amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These &lt;em&gt;mean&lt;/em&gt; the same thing, but if you consider them as two series of bytes, they're different and would therefore result in different signatures. During the parsing and handling of XML data that needs to happen during a SAML authentication flow, it's entirely plausible that two different legal representations of the same data might emerge. There needs to be a way of distinguishing when two XML documents are 'really' the same; that's what &lt;strong&gt;canonicalisation&lt;/strong&gt; does for us.&lt;/p&gt;

&lt;p&gt;However, this is both complicated and difficult. In fact, the SAML specifications lay out three different algorithms for it! Again, this flexibility increases the potential for vulnerability.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flying under the radar with XML comments
&lt;/h3&gt;

&lt;p&gt;A few years ago a new vulnerability was also discovered, which allowed an attacker to masquerade as a fully authenticated user. There's a great write-up of it &lt;a href="https://developer.okta.com/blog/2018/02/27/a-breakdown-of-the-new-saml-authentication-bypass-vulnerability" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but the long and short of it is as follows:&lt;/p&gt;

&lt;p&gt;Not every XML parsing library handles things such as comments consistently, and some canonicalisation algorithms ignore comments. This allows for a malicious user to use comments to alter various aspects of the XML request that gets sent to the Identity Provider. In particular, they could affect the way that the Identity Provider parses the identity of the user who is trying to authenticate.&lt;/p&gt;

&lt;p&gt;But wait! It gets worse: the cryptographic signature is generated over the canonicalised version of the document. Because, in this case, that canonicalisation is ignoring comments, this means that even the "tamper-proof" cryptography won't pick up on the fact that the assertion the attacker is presenting is &lt;em&gt;not&lt;/em&gt; what the IdP signed. Thus, an attacker can present an apparently valid signature over an assertion for an arbitrary user, and authenticate as them.&lt;/p&gt;

&lt;p&gt;These days, many SAML implementations have addressed this vulnerability by switching to XML parsing libraries that handle comments in a safe way, and introducing checks against this specific kind of attack.&lt;/p&gt;

&lt;p&gt;In general, SAML is widely used enough that it's had quite a few eyeballs on it, and - as is often the case with SSO technologies! - if it breaks, you at least won't be the only one in hot water. However, if you're implementing your own SAML system, there are plenty of ways you can leave yourself open to attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the drawbacks?
&lt;/h2&gt;

&lt;p&gt;These security concerns are worth taking seriously; if you're building logic for a Service Provider, you'll need to use a SAML library that addresses them (and keep your eyes peeled for any new vulnerabilities that are discovered). If you're &lt;em&gt;writing&lt;/em&gt; a SAML or XML-parsing library, then you definitely need to make sure you understand and guard against the kind of attacks described above!&lt;/p&gt;

&lt;p&gt;Another obvious drawback is the amount of overhead involved in using SAML for SSO. In theory, it can be as simple as downloading two metadata files and uploading them in the right places, but not all SPs and IdPs let you do this quite so easily. If that's the case, you'll have to understand SAML pretty well in order to get things off the ground. This is one of the reasons for the development of OpenID Connect, the other major technology used to implement SSO, which we'll be covering in the next blog post in this series.&lt;/p&gt;

&lt;p&gt;Of course, none of these drawbacks will affect you if you want to enable SAML SSO for your Anvil apps; we've got out-of-the-box, up-to-date SAML integration. It's a single click to add to your app, and setting up a SAML relationship with your Identity Provider of choice is as straightforward as can be. Check out &lt;a href="https://anvil.works/docs/integrations/saml" rel="noopener noreferrer"&gt;our documentation&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fsaml-not-so-scary%2Fanvil-saml.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fanvil.works%2Fblog%2Fimg%2Fsaml-not-so-scary%2Fanvil-saml.png" alt="On the left, the Services menu showing how to add SAML authentication to your app. On the right, the SAML Configuration page for an app, once the service has been added."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works" rel="noopener noreferrer"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build" rel="noopener noreferrer"&gt;Try Anvil for free!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saml</category>
      <category>sso</category>
      <category>authentication</category>
      <category>security</category>
    </item>
    <item>
      <title>An SSO primer: what is it, and how does it work?</title>
      <dc:creator>Eli Holderness</dc:creator>
      <pubDate>Tue, 01 Mar 2022 17:50:08 +0000</pubDate>
      <link>https://dev.to/anvil/an-sso-primer-what-is-it-and-how-does-it-work-41jl</link>
      <guid>https://dev.to/anvil/an-sso-primer-what-is-it-and-how-does-it-work-41jl</guid>
      <description>&lt;h2&gt;
  
  
  Too many logins spoil the online experience
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fHaCMvB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/sso-what-is-it/limes.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fHaCMvB5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/sso-what-is-it/limes.jpg" alt="If you're someone who's ever changed their name, the magnitude of this problem increases exponentially." width="500" height="665"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine you run a tech company. Your employees have got a bunch of different services that they want to use - a ticketing system, an internal wiki, an online code store, an HR system - the list goes on. These are all genuinely different services, perhaps owned or managed by different entities, so you can't just lump them all into one big app. That's a &lt;em&gt;lot&lt;/em&gt; of accounts per person - and you have to configure them for each new person you hire, every time someones changes their name, or whenever someone leaves the company. If you miss a single account at any of these stages it could be a serious problem. Plus, it's a pain for your employees to have to sign into all of these places every time they clock in for the day. Surely there's got to be a better way!&lt;/p&gt;

&lt;p&gt;What if they only had one account, which let them log in to any of these services? Then, each admin action - a name change, a password reset, setting up or closing out accounts - would only need to happen once, in one place. Suddenly, you have a unique and consistent identity for each employee, and a single source of truth for all their details. And, as a bonus, your employees don't have to remember 6 different passwords and jump through a set of login screens every morning.&lt;/p&gt;

&lt;p&gt;That's the idea behind SSO (which, appropriately, stands for &lt;strong&gt;S&lt;/strong&gt;ingle &lt;strong&gt;S&lt;/strong&gt;ign-&lt;strong&gt;O&lt;/strong&gt;n).&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;SSO depends on the following principle: there is some central entity that manages your identity, and is able to verify that you are who you say you are. Then, other services delegate their authentication to that central identity. The authentication flow goes as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You visit your web service of choice.&lt;/li&gt;
&lt;li&gt;That web service sends you to your SSO identity provider's website, where you log in (if you're not already logged in).&lt;/li&gt;
&lt;li&gt;The identity provider sends you back to the web service, along with some token to prove your identity.&lt;/li&gt;
&lt;li&gt;The web service derives your identity from that token (either cryptographically, or just by asking the identity provider).&lt;/li&gt;
&lt;li&gt;The web service then trusts that you have rightfully authenticated as that identity, because they trust the identity provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to set this up, a relationship between that web service and the identity provider needs to be established &lt;em&gt;before&lt;/em&gt; the web service will trust the identity provider to authenticate users, and so that the identity provider knows what's going on when it gets an authentication request from the web service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mRuqMQBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/sso-what-is-it/michael-scott.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mRuqMQBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://anvil.works/blog/img/sso-what-is-it/michael-scott.jpg" alt="By the grace of SSO, Anvil apps can trust Google to authenticate users for them." width="732" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've set up a relationship between your web service and a central identity provider, any user that has an identity managed by that provider can use it to log in to your web service. If they're already authenticated that identity provider, your web service will be able to authenticate them without any active input from the user. If the user &lt;em&gt;isn't&lt;/em&gt; already authenticated the identity provider, they'll be prompted to do so, and this authentication is the aforementioned Single Sign-On.&lt;/p&gt;

&lt;p&gt;By this mechanism, one identity managed by one service can be used subsequently to authenticate the user with multiple services - &lt;em&gt;without&lt;/em&gt; needing those services to store or verify user credentials directly. Convenient!&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the benefits?
&lt;/h2&gt;

&lt;p&gt;Obviously, it massively reduces user friction. Constantly having to log in to services is a pain, and using a central provider to manage identities means you don't end up with a proliferation of passwords to forget.&lt;/p&gt;

&lt;p&gt;On the business and administration side, it means a lot fewer password reset requests for the IT department to handle, and when somebody needs to change some aspect of their identity - for example, a name change - it only needs to happen in one place. When a new user joins the organisation, or an existing one leaves, there's only one account to worry about, which reduces administrative overhead &lt;em&gt;and&lt;/em&gt; the opportunity to leave stale accounts hanging around as a security risk.&lt;/p&gt;

&lt;p&gt;When it comes to security, you might think that a single set of credentials is far riskier than multiple - after all, they only need to get stolen once, right? However, when done right, SSO can actually &lt;em&gt;reduce&lt;/em&gt; risk. By removing the need for multiple sets of credentials and abstracting the process away from the user, it decreases the viability of several common attacks; for example, imagine one of these web services experiences a security breach. You now don't have to worry about someone stealing your users' passwords and attempting to use them elsewhere, because that web service never saw or needed your users' passwords in the first place.&lt;/p&gt;

&lt;p&gt;SSO also makes &lt;a href="https://anvil.works/blog/two-factor-auth-with-hardware"&gt;two-factor authentication&lt;/a&gt; much more attractive as a prospect, since you only have to do it in one place to see the security benefits across all your services. Moreover, if you delegate your identity management to something like Google, you can rely on &lt;em&gt;their&lt;/em&gt; security engineering budget rather than yours. This means getting access to security features like 2FA (with minimal setup), and &lt;a href="https://riskbasedauthentication.org/"&gt;risk-based authentication&lt;/a&gt; - which smaller service providers will be hard-pressed to set up.&lt;/p&gt;

&lt;h2&gt;
  
  
  SSO isn't a technology, it's a goal
&lt;/h2&gt;

&lt;p&gt;This is all a bit abstract, and that's because SSO, as a standalone concept, is just that; a concept. In my next couple of blog posts, we'll dive into the two most popular technologies used to implement it - SAML and OIDC - and take a closer look at how they work.&lt;/p&gt;

&lt;p&gt;Anvil apps come with several ready-made options for SSO - you can configure a SAML-based relationship with any Identity Provider &lt;a href="https://anvil.works/beta-docs/integrations/saml"&gt;with no fuss&lt;/a&gt;, and several OpenID Identity Providers such as &lt;a href="https://anvil.works/beta-docs/integrations/google/authenticating-users"&gt;Google&lt;/a&gt;, &lt;a href="https://anvil.works/beta-docs/integrations/facebook/linking-facebook-and-anvil"&gt;Facebook&lt;/a&gt; and &lt;a href="https://anvil.works/beta-docs/integrations/microsoft/microsoft-single-sign-on"&gt;Microsoft&lt;/a&gt; are already configured.&lt;/p&gt;

&lt;h2&gt;
  
  
  More about Anvil
&lt;/h2&gt;

&lt;p&gt;If you're new here, welcome! &lt;a href="https://anvil.works"&gt;Anvil&lt;/a&gt; is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just &lt;strong&gt;build it all in Python&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://anvil.works/build"&gt;Try Anvil for free!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>authentication</category>
      <category>security</category>
      <category>sso</category>
    </item>
  </channel>
</rss>
