<?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: milktea02</title>
    <description>The latest articles on DEV Community by milktea02 (@milktea02).</description>
    <link>https://dev.to/milktea02</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%2F11762%2F5224106.png</url>
      <title>DEV Community: milktea02</title>
      <link>https://dev.to/milktea02</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/milktea02"/>
    <language>en</language>
    <item>
      <title>Misunderstanding Go Timer Resets</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Mon, 10 Jun 2024 07:40:51 +0000</pubDate>
      <link>https://dev.to/milktea02/misunderstanding-go-timers-and-channels-1jal</link>
      <guid>https://dev.to/milktea02/misunderstanding-go-timers-and-channels-1jal</guid>
      <description>&lt;p&gt;My teammate shared a snippet of code with me the other day which led to a fun rabbit hole.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR:
&lt;/h2&gt;

&lt;p&gt;Remember to drain your timer channel before resetting it if the reset is not a result of the timer firing a notification (e.g. you read from the  channel)&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Go Timer?
&lt;/h2&gt;

&lt;p&gt;As the name implies, a timer waits a duration of time before firing an event (sending a signal to a channel).&lt;/p&gt;

&lt;p&gt;Timers can be stopped, and reset. Just like in real life!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62ksi2lskirbs5ajhl0k.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62ksi2lskirbs5ajhl0k.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wait for 10 seconds for the timer to send a signal"&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;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It's been 10 seconds!)


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Of course, you could always just use &lt;code&gt;time.Sleep(10 * time.Second)&lt;/code&gt; in the above example. Unlike sleep, you can stop the Timer before the duration has been met.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&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;lt;-&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;
   &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"It's been 10 seconds!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Never mind, don't wait 10 seconds for the timer"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PrintLn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Slept for 15 seconds!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And just like a kitchen timer, you can reset it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// If you're feeling spicy you could reset with a random duration&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&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;h2&gt;
  
  
  Everything makes sense until it doesn't
&lt;/h2&gt;

&lt;p&gt;So, I thought I had Timers understood until my teammate sent me this snippet of code:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&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;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&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="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&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="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&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="p"&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;Maybe you're an expert in timers, channels, and select blocks and can see the bug here.&lt;/p&gt;

&lt;p&gt;At first glance, I would never expect to see &lt;code&gt;!&lt;/code&gt; printed. But here is example output:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ go run main.go
.111!1!1!1111


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Shouldn't the timer reset prevent the &lt;code&gt;!&lt;/code&gt; branch from ever getting executed? Have I been misunderstanding and using reset incorrectly?&lt;/p&gt;

&lt;p&gt;Looking at the documentation for Reset, this is near the top:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For a Timer created with NewTimer, Reset should be invoked only on stopped or expired timers with &lt;strong&gt;drained channels&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;D'oh! Even if the timer has been reset, it doesn't change the fact that it has already fired and so the channel contains an event! And select will pick a branch "randomly" if more than one branch is ready.&lt;/p&gt;

&lt;p&gt;And just a few lines down, we are given instructions on how to use reset:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a program has already received a value from t.C, the timer is known to have expired and the channel drained, so t.Reset can be used directly.&lt;br&gt;
&lt;strong&gt;If a program has not yet received a value from t.C, however, the timer must be stopped and—if Stop reports that the timer expired before being stopped—the channel explicitly drained:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&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;lt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Putting it all together, correctly
&lt;/h2&gt;

&lt;p&gt;Since we did not receive anything from the timer channel, we need to check if the timer has already went off, and if so we should drain the channel before resetting it. Changing the snippet as so:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// drain the channel&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&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="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&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;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&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="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&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="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;Now, all shall be well!&lt;/p&gt;

&lt;p&gt;Example output:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;$ go run main.go&lt;br&gt;
.111111111111111111111&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Resources:&lt;br&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gobyexample.com/timers" rel="noopener noreferrer"&gt;https://gobyexample.com/timers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.22.4:src/time/sleep.go;l=46-53" rel="noopener noreferrer"&gt;https://cs.opensource.google/go/go/+/refs/tags/go1.22.4:src/time/sleep.go;l=46-53&lt;/a&gt;
&lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.22.4:src/time/sleep.go;l=104-105" rel="noopener noreferrer"&gt;https://cs.opensource.google/go/go/+/refs/tags/go1.22.4:src/time/sleep.go;l=104-105&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;As part of this little journey, we also discovered running this snippet on a MacBook Pro 2019 (intel), vs Ubuntu on WSL (intel) yielded consistently different outputs which I may or may not write about once I have all the facts straight.&lt;/p&gt;

&lt;p&gt;Some things I thought about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MacOS vs Ubuntu? MacOS vs Windows? Is this even relevant?&lt;/li&gt;
&lt;li&gt;✨schedulers✨&lt;/li&gt;
&lt;li&gt;Goroutines are not (os) threads. Repeat after me "goroutines are not (os) threads"&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>coding</category>
      <category>learning</category>
    </item>
    <item>
      <title>Consuming and deserializing avro messages with Apache kafka-console-consumer and AWS Glue as the Schema Registry</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Sun, 29 Jan 2023 22:05:24 +0000</pubDate>
      <link>https://dev.to/milktea02/consuming-avro-messages-with-the-kafka-console-consumer-and-aws-glue-as-the-schema-registry-bff</link>
      <guid>https://dev.to/milktea02/consuming-avro-messages-with-the-kafka-console-consumer-and-aws-glue-as-the-schema-registry-bff</guid>
      <description>&lt;p&gt;I had to do this recently and found little to no documentation on what was required to consume avro logs from kafka and deserialize them with the Glue schema registry so I'll document my findings here. For reference, Confluent has one that &lt;a href="https://github.com/confluentinc/schema-registry/blob/master/bin/kafka-avro-console-consumer"&gt;just works out of the box&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Requirements/Pre-requisites/Assumptions/?:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://kafka.apache.org/downloads"&gt;Apache Kafka&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;I think I was using &lt;code&gt;3.3.1&lt;/code&gt; with Scala &lt;code&gt;2.13&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Kafka cluster with topics that have avro messages

&lt;ul&gt;
&lt;li&gt;We are using an AWS MSK cluster with kafka &lt;code&gt;v2.6.x&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;This also assumes the messages are being serialized using the &lt;a href="https://github.com/awslabs/aws-glue-schema-registry/blob/f4f1d8a3f9e0c12da6da07273a1b20f5bfa453e6/common/src/main/java/com/amazonaws/services/schemaregistry/utils/AWSSchemaRegistryConstants.java#L54-L59"&gt;following headers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;AWS Glue Registry with avro schema you're using

&lt;ul&gt;
&lt;li&gt;You can find documentation on how to set this up with some schemas&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;jars from &lt;a href="https://repo1.maven.org/maven2/org/apache/"&gt;&lt;/a&gt;&lt;a href="https://repo1.maven.org/maven2/org/apache/"&gt;https://repo1.maven.org/maven2/org/apache/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;this also assumes you have your iam role permissions/policies configured&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Caveat: This is what worked with our setup and the jars we needed. I don't have any examples or screenshots.&lt;/p&gt;

&lt;p&gt;Download required jars into &lt;code&gt;&amp;lt;location of kafka&amp;gt;/libs/&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;List of jars:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Group Id&lt;/th&gt;
&lt;th&gt;Artifact Id&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;software.amazon.glue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;schema-registry-common&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.1.14&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;software.amazon.glue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;schema-registry-serde&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.1.14&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;software.amazon.awssdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;glue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2.17.12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;software.amazon.awssdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2.17.12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;software.amazon.awssdk&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;url-connection-client&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2.17.12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;org.apache.avro&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;avro&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.11.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;com.google.guava&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;guava&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;30.0-jre&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;com.google.guava&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;failureaccess&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.0.1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Configuring &lt;code&gt;kafka-console-consumer.sh&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;You'll need to supply some properties to the glue deserializer; I've used a wrapper script &lt;code&gt;kafka-glue-avro-console-consumer.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh

kafka-console-consumer.sh --value-deserializer com.amazonaws.services.schemaregistry.deserializers.GlueSchemaRegistryKafkaDeserializer \
        --property value.deserializer.region=&amp;lt;hardcoded-aws-region&amp;gt; \
        --property value.deserializer.dataFormat=AVRO \
        --property value.deserializer.avroRecordType=GENERIC_RECORD "$@"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll need to supply other properties such as &lt;code&gt;--bootstrap-server &amp;lt;list of servers:port&amp;gt;&lt;/code&gt;, &lt;code&gt;--topic &amp;lt;topic-name&amp;gt;&lt;/code&gt;, &lt;code&gt;--consumer.config &amp;lt;config-file&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./kafka-glue-avro-console-consumer.sh --bootstrap-server broker-01:9098 --topic my-topic --consumer.config my-config --max-message 1 --from-beginning
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to specify the glue registry and schema you can do that with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--property value.deserializer.registry.name=&amp;lt;registryName&amp;gt;
--property value.deserializer.schemaName=&amp;lt;schemaName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the source code for additional properties you can use: &lt;a href="https://github.com/awslabs/aws-glue-schema-registry/blob/v1.1.14/common/src/main/java/com/amazonaws/services/schemaregistry/common/configs/GlueSchemaRegistryConfiguration.java"&gt;https://github.com/awslabs/aws-glue-schema-registry/blob/v1.1.14/common/src/main/java/com/amazonaws/services/schemaregistry/common/configs/GlueSchemaRegistryConfiguration.java&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a snippet of &lt;code&gt;ansible&lt;/code&gt; code to grab all the jars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;install artifacts from maven to consume AVRO records&lt;/span&gt;
  &lt;span class="na"&gt;maven_artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.group_id&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.artifact_id&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;item.version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
    &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/home/ubuntu/kafka_{{ kafka_client_version }}/libs/{{ item.artifact_id }}-{{ item.version }}.jar&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0664&lt;/span&gt;
  &lt;span class="na"&gt;loop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;software.amazon.glue'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;schema-registry-common'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;1.1.14&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;software.amazon.glue'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;schema-registry-serde'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;1.1.14&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;software.amazon.awssdk'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;glue'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;2.17.122&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;software.amazon.awssdk'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arns'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;2.17.122&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;software.amazon.awssdk'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;url-connection-client'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;2.17.122&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;org.apache.avro'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;avro'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;1.11.0&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;com.google.guava'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;guava'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;30.0-jre&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;group_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;com.google.guava'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;artifact_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;failureaccess'&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;1.0.1&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(we are testing some things which is why everything is in the user's home directory!)&lt;/p&gt;

</description>
      <category>awsglue</category>
      <category>kafka</category>
      <category>avro</category>
      <category>schema</category>
    </item>
    <item>
      <title>Upgrading to WSL2 (so I can install Rust)</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Mon, 09 May 2022 03:58:28 +0000</pubDate>
      <link>https://dev.to/milktea02/upgrading-to-wsl2-so-i-can-install-rust-24km</link>
      <guid>https://dev.to/milktea02/upgrading-to-wsl2-so-i-can-install-rust-24km</guid>
      <description>&lt;p&gt;TL;DR: Follow this &lt;a href="https://github.com/rust-lang/rustup/issues/2887#issuecomment-1093620664" rel="noopener noreferrer"&gt;guide&lt;/a&gt; someone has kindly posted.&lt;/p&gt;

&lt;p&gt;Trying to install &lt;a href="https://www.rust-lang.org/tools/install" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; and &lt;a href="https://github.com/rust-lang/rustup/issues/2887" rel="noopener noreferrer"&gt;failing&lt;/a&gt; on WSL1 on Windows 11 led me to needing to &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install#upgrade-version-from-wsl-1-to-wsl-2" rel="noopener noreferrer"&gt;upgrade from WSL1 to WSL2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As you can see in my &lt;code&gt;powershell&lt;/code&gt; I'm running version 1 of the wsl:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, step is &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package" rel="noopener noreferrer"&gt;downloading and installing the new kernel package&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Secondly, &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-manual#step-3---enable-virtual-machine-feature" rel="noopener noreferrer"&gt;enabling Virtual Machine feature&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;dism.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/enable-feature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/featurename:VirtualMachinePlatform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/all&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/norestart&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to run powershell as an admin!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Error:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;740&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Elevated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DISM.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;elevated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;complete&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;these&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tasks.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Deployment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Servicing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Management&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Version:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10.0.22000.1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Version:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10.0.22000.556&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Enabling&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;==========================&lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="o"&gt;%==========================&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;successfully.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You  maybe also need to &lt;a href="https://support.microsoft.com/en-us/windows/enable-virtualization-on-windows-11-pcs-c5578302-6e43-4b4b-a449-8ced115f58e1" rel="noopener noreferrer"&gt;enable in BIOS&lt;/a&gt; as well depending on your PC manufacturer. Windows 11 on Lenovo apparently has this enabled by default.&lt;/p&gt;

&lt;p&gt;Now time to install the new kernel we downloaded in step 1:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjftmkwwwup41n8p8i5ge.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjftmkwwwup41n8p8i5ge.png" alt="wsl install prompt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It turns out I also needed to restart my computer for the virtualization enablement to take affect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\WINDOWS\system32&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--set-default-version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Please&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Machine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Platform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Windows&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;feature&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ensure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;virtualization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BIOS.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;please&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://aka.ms/wsl2-install&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to set to version 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\WINDOWS\system32&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--set-default-version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;differences&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WSL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;please&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://aka.ms/wsl2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;operation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;successfully.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oddly enough this didn't work - possibly because I needed to specify which linux distribution I would like to use wsl2?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\WINDOWS\system32&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Stopped&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\WINDOWS\system32&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--set-version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Conversion&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;may&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;take&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;few&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;minutes...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;differences&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WSL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;please&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;visit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://aka.ms/wsl2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Conversion&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;complete.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;PS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\WINDOWS\system32&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wsl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;STATE&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;VERSION&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Stopped&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can I finally install Rust on Ubuntu on WSL 2?&lt;/p&gt;

&lt;p&gt;Something something about running scripts through a &lt;code&gt;cURL&lt;/code&gt; request but it's from &lt;code&gt;rust-lang.org&lt;/code&gt; and you can always take a look at the script from &lt;code&gt;https://sh.rustup.rs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--proto&lt;/span&gt; &lt;span class="s1"&gt;'=https'&lt;/span&gt; &lt;span class="nt"&gt;--tlsv1&lt;/span&gt;.2 &lt;span class="nt"&gt;-sSf&lt;/span&gt; https://sh.rustup.rs | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Rust is installed now. Great!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rustup &lt;span class="nt"&gt;-V&lt;/span&gt;
rustup 1.24.3 &lt;span class="o"&gt;(&lt;/span&gt;ce5817a94 2021-05-31&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;rustc &lt;span class="nt"&gt;--version&lt;/span&gt;
rustc 1.60.0 &lt;span class="o"&gt;(&lt;/span&gt;7737e0b5c 2022-04-04&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;cargo &lt;span class="nt"&gt;--version&lt;/span&gt;
cargo 1.60.0 &lt;span class="o"&gt;(&lt;/span&gt;d1fd9fe 2022-03-01&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ayy!&lt;/p&gt;

</description>
      <category>wsl</category>
      <category>wsl2</category>
      <category>rust</category>
    </item>
    <item>
      <title>Google Sheets to track Dividends (How I pack and search the data after webscraping it)</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Fri, 08 Apr 2022 08:20:44 +0000</pubDate>
      <link>https://dev.to/milktea02/google-sheets-to-track-dividends-how-i-pack-and-search-the-data-after-webscraping-it-1023</link>
      <guid>https://dev.to/milktea02/google-sheets-to-track-dividends-how-i-pack-and-search-the-data-after-webscraping-it-1023</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/milktea02/webscraping-in-google-sheets-4jhm"&gt;last post&lt;/a&gt; I wrote about using Google Sheets to webscrape dividend data from &lt;a href="https://dividendhistory.org" rel="noopener noreferrer"&gt;dividendhistory.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today I'm going to share with you my adventures to improve efficiency and how to store data using sheets &lt;code&gt;TRANSPOSE()&lt;/code&gt; and &lt;code&gt;FLATTEN()&lt;/code&gt; functions and search using &lt;code&gt;MATCH()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TOC&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The improved scrape&lt;/li&gt;
&lt;li&gt;Packing the data&lt;/li&gt;
&lt;li&gt;
Searching the data

&lt;ul&gt;
&lt;li&gt;When am I going to get paid next?&lt;/li&gt;
&lt;li&gt;What about the other data?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Improved Scrape
&lt;/h2&gt;

&lt;p&gt;Before, to scrape the dividend history table I was using the &lt;code&gt;IMPORTHTML()&lt;/code&gt; function but also noted that some times I may make up to two calls because the web page may only have one table instead of two causing essentially an index out of range error.&lt;/p&gt;

&lt;p&gt;After reviewing the page source I found out the table has an &lt;code&gt;id&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;'dividend_table'&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'table table-striped table-bordered'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;thead&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Ex-Dividend Date&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Payout Date&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;Cash Amount&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;th&amp;gt;&lt;/span&gt;% Change&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/thead&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;tbody&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;2022-10-29&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;2022-11-26&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;$1.33**&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;unconfirmed/estimated&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;2022-07-30&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;2022-08-26&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;$1.33**&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;i&amp;gt;&lt;/span&gt;unconfirmed/estimated&lt;span class="nt"&gt;&amp;lt;/i&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;   
    &lt;span class="nt"&gt;&amp;lt;tr&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;2022-04-29&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;2022-05-26&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&lt;/span&gt;$1.33&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;td&amp;gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
...
...
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;d'oh!&lt;/p&gt;

&lt;p&gt;I can use &lt;code&gt;IMPORTXML()&lt;/code&gt; and just query for this table directly!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=IMPORTXML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://dividendhistory.org/payout/TSX/BMO"&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"//table[@id='dividend_table']/*/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And using that query looks like this in Sheets:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj90ug4y1o13koq512u1u.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj90ug4y1o13koq512u1u.png" alt="screenshot of how the query would look like in sheets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can continue to use the &lt;code&gt;INDEX(range, row, col)&lt;/code&gt; function to grab the exact cells you want but for myself I wanted to do a few fun things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packing the data
&lt;/h2&gt;

&lt;p&gt;Now, I only really need some rows of data and I don't really care for the &lt;code&gt;% Change&lt;/code&gt; column, so we use &lt;code&gt;ARRAY_CONSTRAIN(range, rows, cols)&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=ARRAY_CONSTRAIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;IMPORTXML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://dividendhistory.org/payout/TSX/BMO"&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"//table[@id='dividend_table']/*/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n96o3g457qicl47yg7j.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n96o3g457qicl47yg7j.png" alt="after applying array constrain function we only have 6 rows and 3 columns of data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I want to further pack the data so that it occupies it's own row or column which can be done using &lt;code&gt;TRANSPOSE()&lt;/code&gt; and &lt;code&gt;FLATTEN()&lt;/code&gt; and you'll see that order will matter:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71kkhbcldn99by3hdbtj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71kkhbcldn99by3hdbtj.png" alt="Examples of flattening and transposing cells on sheets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We want to apply &lt;code&gt;TRANSPOSE()&lt;/code&gt; first then &lt;code&gt;FLATTEN()&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=FLATTEN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;TRANSPOSE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;ARRAY_CONSTRAIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;IMPORTXML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://dividendhistory.org/payout/TSX/BMO"&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"//table[@id='dividend_table']/*/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Which makes it look like the columns are combined to a stack (hehe stack):&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74uw6tm6nm1six48qmml.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74uw6tm6nm1six48qmml.png" alt="screenshot of data after applying a transpose and flatten"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Searching the Data
&lt;/h2&gt;

&lt;p&gt;If you ever had to take a course on algorithms and data structures you might remember doing a lot of stuff related to pointers and offsets and this is why I stored the data to fit one column!&lt;/p&gt;

&lt;h3&gt;
  
  
  When am I going to get paid next?
&lt;/h3&gt;

&lt;p&gt;I can make use of the &lt;code&gt;MATCH(key, range, [search_type])&lt;/code&gt; formula to search for a relative offset.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfs0n1mukgisvagl3i4z.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfs0n1mukgisvagl3i4z.png" alt="Screenshot of tooltip for using MATCH()"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;search_type&lt;/code&gt; is useful because I want to find the next payout date. To find the date that is equal to or greater than today I can set the &lt;code&gt;search_type&lt;/code&gt; to &lt;code&gt;-1&lt;/code&gt; and luckily for us the dates are already sorted in descending order:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgnv6fmwzq47j3mmgg8p.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvgnv6fmwzq47j3mmgg8p.png" alt="screenshot of tooltip for using MATCH() search_type"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sample of what we're going to do with the data:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futj4o5dlgw0otbqlw5v5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Futj4o5dlgw0otbqlw5v5.png" alt="Screenshot of the sheet getting the next payout date and the amount as well!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As of writing, &lt;code&gt;TODAY()&lt;/code&gt; is &lt;code&gt;2022-04-08&lt;/code&gt; and we can see that the relative offset of the next payout date (&lt;code&gt;2022-05-26&lt;/code&gt;) when searching from &lt;code&gt;B14&lt;/code&gt; to &lt;code&gt;B18&lt;/code&gt; is &lt;code&gt;3&lt;/code&gt; from the top, so located in &lt;code&gt;B16&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=MATCH&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B14&lt;/span&gt;&lt;span class="no"&gt;:B18,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can also get the exact row where &lt;code&gt;Payout Date&lt;/code&gt; starts at using &lt;code&gt;ROW()&lt;/code&gt; (useful if you drag things here and there instead of hardcoding):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=ROW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;B13&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So now we know that the next payout date is located in cell &lt;code&gt;B(13 + 3&lt;/code&gt; but how can we get the information from that cell address?&lt;/p&gt;

&lt;p&gt;We can use the &lt;code&gt;INDIRECT()&lt;/code&gt; function to reference a cell using an address that's in &lt;code&gt;TEXT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Basically we want a generic way to write:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=INDIRECT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"B16"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The cool thing is we can use &lt;code&gt;COLUMN&lt;/code&gt; and &lt;code&gt;INDIRECT()&lt;/code&gt; also accepts address in &lt;code&gt;RyCx&lt;/code&gt; format if we set the optional &lt;code&gt;is_A1_notation&lt;/code&gt; flag to &lt;code&gt;FALSE&lt;/code&gt;. Again I like using &lt;code&gt;&amp;amp;&lt;/code&gt; to build strings in sheets:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=INDIRECT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;B1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMN&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And we can do the same for getting the next Cash Amount by using a different starting offset but same relative offset:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;=INDIRECT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;B2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;B3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"C"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMN&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="n"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  What about the other data?&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;In my last post I also scraped the &lt;code&gt;yield&lt;/code&gt;. I also did this and with a bit of data massaging also tacked it onto the column as you can see here in my raw data spreadsheet example:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftt75rr67kahaeooun3mm.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftt75rr67kahaeooun3mm.png" alt="poor resolution of my data spreadsheet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So ultimately I end up making only two calls to dividend history per ticker symbol which is much better than up-to two calls for the dividend amount, and one call for the yield. We also get all the useful data from the page.&lt;/p&gt;

&lt;p&gt;Here is an example of what you can do with the raw data and only taking the relevant data:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1ahftsdk3hxos8nkx5e.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1ahftsdk3hxos8nkx5e.png" alt="screenshot of a nicer table that uses the raw data as a source"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's all sorts of stuff you can do for example, taking the frequency and calculating how much dividend you could expect from a single share over a year. You can use &lt;code&gt;IF()&lt;/code&gt; to decide if the frequency would be 12 (monthly) or 4 (quarterly).&lt;/p&gt;

&lt;p&gt;And here is a link to the example if you would like to make a copy and check out the stuff for yourself. It's been pre-populated with Canadian banks and some American companies that pay dividends.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.google.com/spreadsheets/d/1CNfWRi7pY5zWcQ1htC5m557oBYS8-YKnMtTuStbhTaQ/edit?usp=drivesdk" rel="noopener noreferrer"&gt;https://docs.google.com/spreadsheets/d/1CNfWRi7pY5zWcQ1htC5m557oBYS8-YKnMtTuStbhTaQ/edit?usp=drivesdk&lt;/a&gt;&lt;/p&gt;

</description>
      <category>googlesheets</category>
      <category>webscraping</category>
      <category>finance</category>
      <category>dividends</category>
    </item>
    <item>
      <title>Webscraping in Google Sheets (to do personal finance)</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Fri, 01 Apr 2022 05:56:00 +0000</pubDate>
      <link>https://dev.to/milktea02/webscraping-in-google-sheets-4jhm</link>
      <guid>https://dev.to/milktea02/webscraping-in-google-sheets-4jhm</guid>
      <description>&lt;p&gt;TL;DR: use &lt;code&gt;IMPORTHTML()&lt;/code&gt; and &lt;code&gt;IMPORTXML()&lt;/code&gt; to webscrape :)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TOC&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bob's Your Uncle&lt;/li&gt;
&lt;li&gt;
My Solution

&lt;ul&gt;
&lt;li&gt;Scraping for yield&lt;/li&gt;
&lt;li&gt;
Scraping for dividend ($)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;References&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Did you know you can webscrape using Google Sheets? Me neither, but it's the year 2022 and we have 9 more months in this year to learn so many new random things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bob's your uncle
&lt;/h2&gt;

&lt;p&gt;I enjoy reading about personal finance and one such person I enjoy reading posts from is Bob at Tawcan.com. He has a &lt;a href="https://www.tawcan.com/using-google-spreadsheet-dividend-investment/#Even_Newer_Formula1" rel="noopener noreferrer"&gt;post&lt;/a&gt; detailing how he uses &lt;code&gt;IMPORTHTML()&lt;/code&gt; and &lt;code&gt;IMPORTXML()&lt;/code&gt; to scrape dividend data from Google Finance and Yahoo Finance. This is really useful since the built in &lt;code&gt;GOOGLEFINANCE()&lt;/code&gt; function doesn't have this information.&lt;/p&gt;

&lt;p&gt;I ended up modifying what he had and also had to learn about &lt;code&gt;XPath&lt;/code&gt; and &lt;code&gt;XQuery&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is one example of a cell function he uses to get the dividend and yield information from Yahoo Finance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=SPLIT(INDEX(IMPORTHTML(concatenate("https://finance.yahoo.com/quote/",B2),"table",2),6,2)," ")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;IMPORTHTML()&lt;/code&gt; you only get a choice of scraping for &lt;code&gt;"table"&lt;/code&gt; or &lt;code&gt;"list"&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In the above example, &lt;code&gt;B2&lt;/code&gt; contains a stock ticker symbol like &lt;code&gt;RY&lt;/code&gt; which is concatenated with the &lt;code&gt;url&lt;/code&gt; to the page we want scraped. We end up getting the &lt;code&gt;2&lt;/code&gt;nd table on the page with &lt;code&gt;IMPORTHTML()&lt;/code&gt;. Sheets ends up importing the table which isn't very useful for us so we further parse the table using &lt;code&gt;INDEX()&lt;/code&gt; to get the exact cell we want. In this case the dividend yield information is the 6th row, and 2nd column with the index starting from &lt;code&gt;1&lt;/code&gt;. That returns a dividend and yield so we further &lt;code&gt;SPLIT()&lt;/code&gt; that information.&lt;/p&gt;

&lt;p&gt;If you check out Bob's post, you'll see that he constantly needs to update his formulas because Google Finance and Yahoo Finance keep updating layouts. He also uses &lt;code&gt;IMPORTXML()&lt;/code&gt; at some point because the pages are dynamic and don't usually have that information statically available.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Solution
&lt;/h2&gt;

&lt;p&gt;I decided to find other sources for dividend and yield and came across &lt;a href="https://dividendhistory.org" rel="noopener noreferrer"&gt;dividend history&lt;/a&gt;. What's nice is that this source also has dividend and yield information for ETFs which isn't the case for Google and Yahoo Finance. I don't know how often the layout is updated but given how simple it is and how it serves a single purpose, I assume it won't be updated too often.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl6wqrelvalo78tpfzqw.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frl6wqrelvalo78tpfzqw.png" alt="Screenshot of a page on dividendhistory.org showing dividend information for The Royal Bank of Canada stock"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping for Yield
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=INDEX(SPLIT(IMPORTXML("https://dividendhistory.org/payout/"&amp;amp;IF($B2="NASDAQ", "", "TSX/")&amp;amp;$A2, "//p[contains(text(), 'Yield')]", "en_US"), ":%"), 1, 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my use case, I like to keep ticker symbols in column A, and their exchanges in column B. This is important because Canadian stocks (TSX) are found in &lt;code&gt;payout/TSX/&amp;lt;tickersymbol&amp;gt;&lt;/code&gt; whereas American stocks are in &lt;code&gt;payout/&amp;lt;tickersymbol&amp;gt;&lt;/code&gt;. I also don't use &lt;code&gt;CONCATENATE()&lt;/code&gt; and prefer to just use &lt;code&gt;"&amp;lt;string&amp;gt;"&amp;amp;A1&amp;amp;"&amp;lt;string&amp;gt;"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The second argument in &lt;code&gt;IMPORTXML()&lt;/code&gt; is the &lt;code&gt;xquery_path&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//p[contains(text(), 'Yield')]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thankfully HTML is basically just a very specific XML amirite? Anyway the query looks for any &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; that contains the text value &lt;code&gt;'Yield'&lt;/code&gt; between the tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Yield: 1.23%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And since I only want the numbers I &lt;code&gt;SPLIT()&lt;/code&gt; at the &lt;code&gt;:&lt;/code&gt; and &lt;code&gt;%&lt;/code&gt; and take the second element (remember in Sheets, index starts at 1).&lt;/p&gt;

&lt;h2&gt;
  
  
  Scraping for Dividend ($)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=INDEX(IMPORTHTML("https://dividendhistory.org/payout/"&amp;amp;IF($B2="NASDAQ", "", "TSX/")&amp;amp;$A2, "table", 2, "us_EN"), 4, 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dividend is easier since I can use &lt;code&gt;IMPORTHTML()&lt;/code&gt; and select the exact cell from the &lt;code&gt;2&lt;/code&gt;nd table on the page.&lt;/p&gt;

&lt;p&gt;This isn't perfect because some tickers don't have any news or announcements, as is the case for &lt;code&gt;VGRO&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjhao9mg44gx4or3kc75.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjhao9mg44gx4or3kc75.png" alt="Another screenshot of dividend history but for VGRO ETF ticker"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, the dividend history table is actually the &lt;code&gt;1&lt;/code&gt;st table on the page. We end up with a reference error because I'm looking for a &lt;code&gt;2&lt;/code&gt;nd table that doesn't exist (out of bounds!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#REF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My first solution to this problem was thinking maybe all ETFs or even REITs don't usually have announcements so I can track a column for the &lt;code&gt;TYPE&lt;/code&gt; of investment and pick &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; accordingly. This proved to be an incorrect assumption. &lt;/p&gt;

&lt;p&gt;My second solution was to make the first &lt;code&gt;IMPORTHTML()&lt;/code&gt; request and if &lt;code&gt;ISERR(&amp;lt;request&amp;gt;)&lt;/code&gt; then make a second request searching for the &lt;code&gt;1&lt;/code&gt;st table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=IF(ISERR(G2),INDEX(IMPORTHTML("https://dividendhistory.org/payout/"&amp;amp;IF($B2="NASDAQ", "", "TSX/")&amp;amp;$A2, "table", 1, "us_EN"), 4, 3), G2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is really inefficient because it means making up to 2 requests for a single value. I stored the first request in column &lt;code&gt;G&lt;/code&gt; and call it the "test" column:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbva91eo2u5zncvwjcwdj.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbva91eo2u5zncvwjcwdj.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyway, that was a fun little rabbit hole and I think I'll find many uses for webscraping on sheets that may or may not involve personal finance!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.tawcan.com/using-google-spreadsheet-dividend-investment/#Even_Newer_Formula1" rel="noopener noreferrer"&gt;https://www.tawcan.com/using-google-spreadsheet-dividend-investment/#Even_Newer_Formula1&lt;/a&gt;&lt;br&gt;
&lt;a href="https://support.google.com/docs/answer/3093281?hl=en" rel="noopener noreferrer"&gt;https://support.google.com/docs/answer/3093281?hl=en&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.w3schools.com/xml/xpath_syntax.asp" rel="noopener noreferrer"&gt;https://www.w3schools.com/xml/xpath_syntax.asp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>googlesheets</category>
      <category>webscraping</category>
      <category>finance</category>
      <category>xquery</category>
    </item>
    <item>
      <title>Back on the struggle but with pip and Ansible! (what is _ctypes?)</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Mon, 21 Mar 2022 08:20:17 +0000</pubDate>
      <link>https://dev.to/milktea02/back-on-the-struggle-but-with-pip-and-ansible-what-is-ctypes-1blm</link>
      <guid>https://dev.to/milktea02/back-on-the-struggle-but-with-pip-and-ansible-what-is-ctypes-1blm</guid>
      <description>&lt;p&gt;TL;DR: If you're getting the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from _ctypes import Union, Structure, Array
    ModuleNotFoundError: No module named '_ctypes'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you're probably missing &lt;code&gt;libffi-dev&lt;/code&gt; on Ubuntu (or some variation on other OS's)&lt;/p&gt;




&lt;p&gt;And we're back! &lt;a href="https://dev.to/milktea02/struggle-tweets-to-install-python-3102-with-pyenv-on-ubuntu-2004-wsl-3ek5"&gt;Last time&lt;/a&gt; I was trying to install python &lt;code&gt;v3.10.2&lt;/code&gt; with &lt;code&gt;pyenv&lt;/code&gt; and was missing a million dependencies.&lt;/p&gt;

&lt;p&gt;This time I'm trying to install &lt;code&gt;ansible&lt;/code&gt; using &lt;code&gt;pip&lt;/code&gt; (managed with &lt;code&gt;pyenv&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Collecting ansible
  Downloading ansible-5.5.0.tar.gz &lt;span class="o"&gt;(&lt;/span&gt;42.0 MB&lt;span class="o"&gt;)&lt;/span&gt;
     |████████████████████████████████| 42.0 MB 782 kB/s
    ERROR: Command errored out with &lt;span class="nb"&gt;exit &lt;/span&gt;status 1:
     &lt;span class="nb"&gt;command&lt;/span&gt;: /home/banana/.pyenv/versions/3.10.2/bin/python3.10 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'import io, os, sys, setuptools, tokenize; sys.argv[0] = '&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'/tmp/pip-install-cfmis9e2/ansible_27dc97f765544a6381b36454d1ed76c5/setup.py'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'; __file__='&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'/tmp/pip-install-cfmis9e2/ansible_27dc97f765544a6381b36454d1ed76c5/setup.py'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;';f = getattr(tokenize, '&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'open'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;', open)(__file__) if os.path.exists(__file__) else io.StringIO('&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'from setuptools import setup; setup()'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;');code = f.read().replace('&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'\r\n'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'\n'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;');f.close();exec(compile(code, __file__, '&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'exec'&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="s1"&gt;'))'&lt;/span&gt; egg_info &lt;span class="nt"&gt;--egg-base&lt;/span&gt; /tmp/pip-pip-egg-info-e10880nb
         cwd: /tmp/pip-install-cfmis9e2/ansible_27dc97f765544a6381b36454d1ed76c5/
    Complete output &lt;span class="o"&gt;(&lt;/span&gt;11 lines&lt;span class="o"&gt;)&lt;/span&gt;:
    Traceback &lt;span class="o"&gt;(&lt;/span&gt;most recent call last&lt;span class="o"&gt;)&lt;/span&gt;:
      File &lt;span class="s2"&gt;"&amp;lt;string&amp;gt;"&lt;/span&gt;, line 1, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
      File &lt;span class="s2"&gt;"/home/banana/.pyenv/versions/3.10.2/lib/python3.10/site-packages/setuptools/__init__.py"&lt;/span&gt;, line 18, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
        from setuptools.dist import Distribution
      File &lt;span class="s2"&gt;"/home/banana/.pyenv/versions/3.10.2/lib/python3.10/site-packages/setuptools/dist.py"&lt;/span&gt;, line 38, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
        from setuptools import windows_support
      File &lt;span class="s2"&gt;"/home/banana/.pyenv/versions/3.10.2/lib/python3.10/site-packages/setuptools/windows_support.py"&lt;/span&gt;, line 2, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
        import ctypes
      File &lt;span class="s2"&gt;"/home/banana/.pyenv/versions/3.10.2/lib/python3.10/ctypes/__init__.py"&lt;/span&gt;, line 8, &lt;span class="k"&gt;in&lt;/span&gt; &amp;lt;module&amp;gt;
        from _ctypes import Union, Structure, Array
    ModuleNotFoundError: No module named &lt;span class="s1"&gt;'_ctypes'&lt;/span&gt;
    &lt;span class="nt"&gt;----------------------------------------&lt;/span&gt;
WARNING: Discarding https://files.pythonhosted.org/packages/b5/6e/5806eafaa71ab5471cfc390089a89c7815ab841657d6517fd72df3d41862/ansible-5.5.0.tar.gz#sha256&lt;span class="o"&gt;=&lt;/span&gt;b8a76d737889c9bfd0e6b0f2276dcf8d836da667067a355776f3504d7a66d518 &lt;span class="o"&gt;(&lt;/span&gt;from https://pypi.org/simple/ansible/&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;requires-python:&amp;gt;&lt;span class="o"&gt;=&lt;/span&gt;3.8&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; Command errored out with &lt;span class="nb"&gt;exit &lt;/span&gt;status 1: python setup.py egg_info Check the logs &lt;span class="k"&gt;for &lt;/span&gt;full &lt;span class="nb"&gt;command &lt;/span&gt;output.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This continues for a bit as &lt;code&gt;pip&lt;/code&gt; tries to install versions of ansible in decreasing order.&lt;/p&gt;

&lt;p&gt;What if I try to install this missing &lt;code&gt;_ctypes&lt;/code&gt; module?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;_ctypes
ERROR: Invalid requirement: &lt;span class="s1"&gt;'_ctypes'&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ctypes
ERROR: Could not find a version that satisfies the requirement ctypes &lt;span class="o"&gt;(&lt;/span&gt;from versions: none&lt;span class="o"&gt;)&lt;/span&gt;
ERROR: No matching distribution found &lt;span class="k"&gt;for &lt;/span&gt;ctypes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;huh, weird&lt;/p&gt;

&lt;p&gt;What is this &lt;code&gt;_ctypes&lt;/code&gt; module that I'm missing? According to the &lt;a href="https://docs.python.org/3/library/ctypes.html"&gt;docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ctypes is a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What does that even mean? My understanding is that the &lt;code&gt;ctypes&lt;/code&gt; library allows python code to use stuff in DLLs (dynamic linked libraries, this is OS dependent) directly using python without needing custom python code. This is really powerful and you can read more about it in the Python docs.&lt;/p&gt;

&lt;p&gt;But why doesn't &lt;code&gt;_ctypes&lt;/code&gt; or &lt;code&gt;ctypes&lt;/code&gt; exist in pip as an installable module? Well, &lt;code&gt;_ctypes&lt;/code&gt; is a built-in library so there isn't any module to &lt;code&gt;pip install&lt;/code&gt;. What we're missing is the &lt;a href="https://packages.ubuntu.com/focal/libffi-dev"&gt;&lt;code&gt;libffi-dev&lt;/code&gt;&lt;/a&gt; Ubuntu package (thanks stackoverflow!):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Foreign Function Interface library (development files)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's hit up &lt;code&gt;apt install libffi-dev&lt;/code&gt;. Then do another &lt;code&gt;pip install ansible&lt;/code&gt; (if you want to save time you'd just try &lt;code&gt;from ctypes import *&lt;/code&gt; in a python shell and find that the module still can't be found):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ansible
Collecting ansible
  Using cached ansible-5.5.0.tar.gz &lt;span class="o"&gt;(&lt;/span&gt;42.0 MB&lt;span class="o"&gt;)&lt;/span&gt;
  Preparing metadata &lt;span class="o"&gt;(&lt;/span&gt;setup.py&lt;span class="o"&gt;)&lt;/span&gt; ... error
  error: subprocess-exited-with-error

  × python setup.py egg_info did not run successfully.
  │ &lt;span class="nb"&gt;exit &lt;/span&gt;code: 1
  ╰─&amp;gt; &lt;span class="o"&gt;[&lt;/span&gt;1 lines of output]
      ERROR: Can not execute &lt;span class="sb"&gt;`&lt;/span&gt;setup.py&lt;span class="sb"&gt;`&lt;/span&gt; since setuptools is not available &lt;span class="k"&gt;in &lt;/span&gt;the build environment.
      &lt;span class="o"&gt;[&lt;/span&gt;end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error &lt;span class="k"&gt;while &lt;/span&gt;generating package metadata.
╰─&amp;gt; See above &lt;span class="k"&gt;for &lt;/span&gt;output.

note: This is an issue with the package mentioned above, not pip.
hint: See above &lt;span class="k"&gt;for &lt;/span&gt;details.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interesting. What is also interesting was the error I got &lt;a href="https://dev.to/milktea02/struggle-tweets-to-install-python-3102-with-pyenv-on-ubuntu-2004-wsl-3ek5"&gt;last time&lt;/a&gt; when I was trying to install &lt;code&gt;python&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to build these modules:
_ctypes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the &lt;code&gt;zlib&lt;/code&gt; package previously I was still able to successfully compile python without &lt;code&gt;libffi&lt;/code&gt; and also did not get an error. I'm wondering now if my installation of python &lt;code&gt;3.10.2&lt;/code&gt; is a bit wonky now.&lt;/p&gt;

&lt;p&gt;I've decided to take a gander at what modules I have and while I don't see any &lt;code&gt;_ctypes.py&lt;/code&gt; or &lt;code&gt;ctypes.py&lt;/code&gt; I did find a directory called &lt;code&gt;ctype&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.pyenv/versions/3.10.2/lib/python3.10/ctypes&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls
&lt;/span&gt;__init__.py  __pycache__  _aix.py  _endian.py  macholib  &lt;span class="nb"&gt;test  &lt;/span&gt;util.py  wintypes.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm not sure if any of the above is suspicious but I thought I'd take a look anyway.&lt;/p&gt;

&lt;p&gt;I also have a hunch that with &lt;code&gt;libffi&lt;/code&gt; missing during my initial python install (failed silently??), the appropriate symbolic links may not have been created properly or python wasn't compiled properly so I'll do a &lt;code&gt;pyenv uninstall 3.10.2&lt;/code&gt; and &lt;code&gt;pyenv install 3.10.2&lt;/code&gt; to recompile.&lt;/p&gt;

&lt;p&gt;Now to check if &lt;code&gt;ctypes&lt;/code&gt; was successfully built:&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;Python&lt;/span&gt; &lt;span class="mf"&gt;3.10&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="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Mar&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt; &lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;55&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;GCC&lt;/span&gt; &lt;span class="mf"&gt;9.4&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;on&lt;/span&gt; &lt;span class="n"&gt;linux&lt;/span&gt;
&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="s"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"copyright"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"credits"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s"&gt;"license"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;information&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="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ctypes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;libc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CDLL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"libc.so.6"&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;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="mi"&gt;1647848336&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;yay success!&lt;/p&gt;

&lt;p&gt;NOW, back to installing &lt;code&gt;ansible&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;ansible
...
... lots of output
...
&lt;span class="k"&gt;done
&lt;/span&gt;Successfully installed MarkupSafe-2.1.1 PyYAML-6.0 ansible-5.5.0 ansible-core-2.12.3 cffi-1.15.0 cryptography-36.0.2 jinja2-3.0.3 packaging-21.3 pycparser-2.21 pyparsing-3.0.7 resolvelib-0.5.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Excellent, and all the dependencies were installed too!&lt;/p&gt;

</description>
      <category>pyenv</category>
      <category>python</category>
      <category>pip</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>struggle tweets to install python 3.10.2 with pyenv on Ubuntu 20.04 (WSL)</title>
      <dc:creator>milktea02</dc:creator>
      <pubDate>Sun, 13 Mar 2022 01:17:40 +0000</pubDate>
      <link>https://dev.to/milktea02/struggle-tweets-to-install-python-3102-with-pyenv-on-ubuntu-2004-wsl-3ek5</link>
      <guid>https://dev.to/milktea02/struggle-tweets-to-install-python-3102-with-pyenv-on-ubuntu-2004-wsl-3ek5</guid>
      <description>&lt;p&gt;If you want to watch me struggle, continue below. Otherwise just go here: &lt;a href="https://computingforgeeks.com/how-to-install-python-on-ubuntu-linux-system/" rel="noopener noreferrer"&gt;https://computingforgeeks.com/how-to-install-python-on-ubuntu-linux-system/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I just bought a new laptop and figured, setting up my WSL Ubuntu environment should be pretty straightforward right? All I need to do is &lt;code&gt;git clone&lt;/code&gt; a few repos and setup my &lt;code&gt;$PATH&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I was very wrong.&lt;/p&gt;

&lt;p&gt;I'm not an expert in setting up Linux environments and it just so happened that Stackoverflow was going through some things (&lt;a href="https://twitter.com/StackStatus/status/1502788125285879817" rel="noopener noreferrer"&gt;https://twitter.com/StackStatus/status/1502788125285879817&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Anyway, some of the things I needed to get my &lt;code&gt;pyenv v2.2.4&lt;/code&gt; to even install &lt;code&gt;python v3.10.2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;At this point I've already &lt;code&gt;apt install&lt;/code&gt; the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

gcc
make
build-essential


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;but I'm still getting the following error:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;pyenv &lt;span class="nb"&gt;install &lt;/span&gt;3.10.2
Downloading Python-3.10.2.tar.xz...
-&amp;gt; https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tar.xz
Installing Python-3.10.2...

BUILD FAILED &lt;span class="o"&gt;(&lt;/span&gt;Ubuntu 20.04 using python-build 2.2.4&lt;span class="o"&gt;)&lt;/span&gt;

Inspect or clean up the working tree at /tmp/python-build.20220312160907.27360
Results logged to /tmp/python-build.20220312160907.27360.log

Last 10 log lines:
  File &lt;span class="s2"&gt;"/tmp/python-build.20220312160907.27360/Python-3.10.2/Lib/ensurepip/__init__.py"&lt;/span&gt;, line 277, &lt;span class="k"&gt;in &lt;/span&gt;_main
    &lt;span class="k"&gt;return &lt;/span&gt;_bootstrap&lt;span class="o"&gt;(&lt;/span&gt;
  File &lt;span class="s2"&gt;"/tmp/python-build.20220312160907.27360/Python-3.10.2/Lib/ensurepip/__init__.py"&lt;/span&gt;, line 193, &lt;span class="k"&gt;in &lt;/span&gt;_bootstrap
    &lt;span class="k"&gt;return &lt;/span&gt;_run_pip&lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;args, &lt;span class="k"&gt;*&lt;/span&gt;_PACKAGE_NAMES], additional_paths&lt;span class="o"&gt;)&lt;/span&gt;
  File &lt;span class="s2"&gt;"/tmp/python-build.20220312160907.27360/Python-3.10.2/Lib/ensurepip/__init__.py"&lt;/span&gt;, line 93, &lt;span class="k"&gt;in &lt;/span&gt;_run_pip
    &lt;span class="k"&gt;return &lt;/span&gt;subprocess.run&lt;span class="o"&gt;([&lt;/span&gt;sys.executable, &lt;span class="s1"&gt;'-W'&lt;/span&gt;, &lt;span class="s1"&gt;'ignore::DeprecationWarning'&lt;/span&gt;,
  File &lt;span class="s2"&gt;"/tmp/python-build.20220312160907.27360/Python-3.10.2/Lib/subprocess.py"&lt;/span&gt;, line 524, &lt;span class="k"&gt;in &lt;/span&gt;run
    raise CalledProcessError&lt;span class="o"&gt;(&lt;/span&gt;retcode, process.args,
subprocess.CalledProcessError: Command &lt;span class="s1"&gt;'['&lt;/span&gt;/tmp/python-build.20220312160907.27360/Python-3.10.2/python&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="nt"&gt;-W&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;ignore::DeprecationWarning&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="nt"&gt;-c&lt;/span&gt;&lt;span class="s1"&gt;', '&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;import runpy&lt;span class="se"&gt;\n&lt;/span&gt;import sys&lt;span class="se"&gt;\n&lt;/span&gt;sys.path &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;/tmp/tmpbfu6lr32/setuptools-58.1.0-py3-none-any.whl&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;/tmp/tmpbfu6lr32/pip-21.2.4-py3-none-any.whl&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; + sys.path&lt;span class="se"&gt;\n&lt;/span&gt;sys.argv[1:] &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="nt"&gt;--no-index&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="nt"&gt;--find-links&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;/tmp/tmpbfu6lr32&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="nt"&gt;--root&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;/&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="nt"&gt;--upgrade&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;setuptools&lt;span class="se"&gt;\'&lt;/span&gt;, &lt;span class="se"&gt;\'&lt;/span&gt;pip&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;runpy.run_module&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"pip"&lt;/span&gt;, &lt;span class="nv"&gt;run_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__main__"&lt;/span&gt;, &lt;span class="nv"&gt;alter_sys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;True&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;']'&lt;/span&gt; returned non-zero &lt;span class="nb"&gt;exit &lt;/span&gt;status 1.
make: &lt;span class="k"&gt;***&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;Makefile:1280: &lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; Error 1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Looking at the logs provided, indeed I am missing a lott of tools:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; /tmp/python-build.20220312160907.27360.log | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"hecking.*no$"&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
197


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I'm just looking blindly through and find the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

ModuleNotFoundError: No module named 'zlib'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "&amp;lt;frozen zipimport&amp;gt;", line 618, in _get_data
  File "&amp;lt;frozen zipimport&amp;gt;", line 573, in _get_decompress_func
zipimport.ZipImportError: can't decompress data; zlib not available


&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;

The necessary bits to build these optional modules were not found:
_bz2                  _curses               _curses_panel
_dbm                  _gdbm                 _hashlib
_lzma                 _sqlite3              _ssl
_tkinter              _uuid                 readline
zlib
To find the necessary bits, look in setup.py in detect_modules() for the module's name.


The following modules found by detect_modules() in setup.py, have been
built by the Makefile instead, as configured by the Setup files:
_abc                  pwd                   time


Failed to build these modules:
_ctypes


Could not build the ssl module!
Python requires a OpenSSL 1.1.1 or newer


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;okay, what is zlib? &lt;a href="https://packages.ubuntu.com/source/focal/zlib" rel="noopener noreferrer"&gt;https://packages.ubuntu.com/source/focal/zlib&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Not too helpful, as there are a bunch of different packages here that I can install, but which one?&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5qkuy7escksrt7a8wew.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj5qkuy7escksrt7a8wew.png" alt="Image screen snippet of the ubuntu packages search for zlib which shows several zlib packages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The internet seems to say &lt;code&gt;zlib1g-dev&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I suppose I'll need to get the dev versions of all these C library packages:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

zlib1g-dev
libbz2-dev
libsqlite3-dev
libgdbm-dev
libssl-dev
libncurses5-dev
libreadline-dev
liblzma-dev


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Anyway, since I know nothing and am just meandering through this on my own even though I can copy paste the list of dependencies someone else has posted on the internet, I decide to only install &lt;code&gt;zlib1g-dev&lt;/code&gt; since the other ones are required for optional modules (which I'll probably need later and regret not installing now).&lt;/p&gt;

&lt;p&gt;Okay so what happens when I try to &lt;code&gt;pyenv install 3.10.2&lt;/code&gt; now?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;pyenv &lt;span class="nb"&gt;install &lt;/span&gt;3.10.2
Downloading Python-3.10.2.tar.xz...
-&amp;gt; https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tar.xz
Installing Python-3.10.2...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?

Please consult to the Wiki page to fix the problem.
https://github.com/pyenv/pyenv/wiki/Common-build-problems


BUILD FAILED &lt;span class="o"&gt;(&lt;/span&gt;Ubuntu 20.04 using python-build 2.2.4&lt;span class="o"&gt;)&lt;/span&gt;

Inspect or clean up the working tree at /tmp/python-build.20220312165507.7502
Results logged to /tmp/python-build.20220312165507.7502.log

Last 10 log lines:
Installing collected packages: setuptools, pip
  WARNING: Value &lt;span class="k"&gt;for &lt;/span&gt;scheme.headers does not match. Please report this to &amp;lt;https://github.com/pypa/pip/issues/10151&amp;gt;
  distutils: /home/banana/.pyenv/versions/3.10.2/include/python3.10/setuptools
  sysconfig: /tmp/python-build.20220312165507.7502/Python-3.10.2/Include/setuptools
  WARNING: Value &lt;span class="k"&gt;for &lt;/span&gt;scheme.headers does not match. Please report this to &amp;lt;https://github.com/pypa/pip/issues/10151&amp;gt;
  distutils: /home/banana/.pyenv/versions/3.10.2/include/python3.10/pip
  sysconfig: /tmp/python-build.20220312165507.7502/Python-3.10.2/Include/pip
  WARNING: The scripts pip3 and pip3.10 are installed &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;'/home/banana/.pyenv/versions/3.10.2/bin'&lt;/span&gt; which is not on PATH.
  Consider adding this directory to PATH or, &lt;span class="k"&gt;if &lt;/span&gt;you prefer to suppress this warning, use &lt;span class="nt"&gt;--no-warn-script-location&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Successfully installed pip-21.2.4 setuptools-58.1.0


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Okay that seems like a more positive step. The only error that I see now is that ssl extensions was not compiled. Seems important. Let's install &lt;code&gt;libssl-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Okay AGAIN:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Downloading Python-3.10.2.tar.xz...
-&amp;gt; https://www.python.org/ftp/python/3.10.2/Python-3.10.2.tar.xz
Installing Python-3.10.2...

WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
Installed Python-3.10.2 to /home/banana/.pyenv/versions/3.10.2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;YAY!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ pyenv versions
* system (set by /home/banana/.pyenv/version)
  3.10.2


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We'll ignore all the warnings... until next time.&lt;/p&gt;

</description>
      <category>python</category>
      <category>pyenv</category>
      <category>ubuntu</category>
      <category>wsl</category>
    </item>
  </channel>
</rss>
